Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 Округление  [new]
Stanislav
Member

Откуда: Донецк
Сообщений: 631
Всем привет!
Есть проблема округления значения в C# и Cи, хотелось бы добиться однозначности при округлении.
Есть значение 7.5077946401986963f в C# =7.507795, а в Си =7,50779486.
Можно ли в C# указать какие-то правила округления для float ?
15 окт 15, 10:10    [18281350]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 22381
Stanislav
Есть значение 7.5077946401986963f в C# =7.507795

хм
Console.WriteLine(Math.Round(7.5077946401986963f, 8));

7,50779486
15 окт 15, 10:24    [18281411]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Stanislav
Member

Откуда: Донецк
Сообщений: 631
Shocker.Pro
Stanislav
Есть значение 7.5077946401986963f в C# =7.507795

хм
Console.WriteLine(Math.Round(7.5077946401986963f, 8));

7,50779486


хм. Спасибо!
Round я не додумался сделать )
15 окт 15, 10:31    [18281444]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 22381
Stanislav
Round я не додумался сделать
Stanislav
Есть проблема округления значения
а что тогда подразумевается под округлением?
15 окт 15, 10:35    [18281460]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Stanislav
Member

Откуда: Донецк
Сообщений: 631
Shocker.Pro
Stanislav
Round я не додумался сделать
Stanislav
Есть проблема округления значения
а что тогда подразумевается под округлением?

Debug.WriteLine(7.5077946401986963f);
15 окт 15, 10:40    [18281481]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 22381
Ну то есть ты фактически делаешь ToString()
Ему тоже можно задать параметры форматирования строки
15 окт 15, 10:49    [18281536]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Stanislav
Member

Откуда: Донецк
Сообщений: 631
Shocker.Pro
Ну то есть ты фактически делаешь ToString()
Ему тоже можно задать параметры форматирования строки

Получатся если так
Debug.WriteLine(7.5077946401986963f); 
тип
float

а так
Console.WriteLine(Math.Round(7.5077946401986963f, 8));
тип
double
15 окт 15, 10:58    [18281594]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 22381
Нет. В обоих случаях тип String

Просто не используй неявные преобразования, и будет тебя щастье
15 окт 15, 11:16    [18281684]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Stanislav
Member

Откуда: Донецк
Сообщений: 631
Shocker.Pro
Нет. В обоих случаях тип String

Просто не используй неявные преобразования, и будет тебя щастье

да string, но в одном случае он получился через float в другом через double.
15 окт 15, 11:33    [18281804]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 4206
Stanislav
Shocker.Pro
Нет. В обоих случаях тип String

Просто не используй неявные преобразования, и будет тебя щастье

да string, но в одном случае он получился через float в другом через double.

если нужна большая точность чем double, используйте decimal, для float методов у Math нет
15 окт 15, 11:55    [18281951]     Ответить | Цитировать Сообщить модератору
Между сообщениями интервал более 1 года.
 Re: Округление  [new]
fortibransa
Member

Откуда: СПб
Сообщений: 22917
Гыыыыы
        static void Main(string[] args)
        {
            double[] values = { 2.125, 2.135, 2.145, 3.125, 3.135, 3.145 };
            foreach (double value in values)
                Console.WriteLine("{0}   AwayFromZero --> {1}   ToEven --> {2} string.Format(\"F:2\") --> {0:F2}", value,
                                  Math.Round(value, 2, MidpointRounding.AwayFromZero),  Math.Round(value, 2, MidpointRounding.ToEven));
            Console.ReadLine();
        }


Результат:

2,125 AwayFromZero --> 2,13 ToEven --> 2,12 string.Format("F:2") --> 2,13
2,135 AwayFromZero --> 2,13 ToEven --> 2,13 string.Format("F:2") --> 2,14
2,145 AwayFromZero --> 2,15 ToEven --> 2,14 string.Format("F:2") --> 2,15
3,125 AwayFromZero --> 3,13 ToEven --> 3,12 string.Format("F:2") --> 3,13
3,135 AwayFromZero --> 3,14 ToEven --> 3,14 string.Format("F:2") --> 3,14
3,145 AwayFromZero --> 3,15 ToEven --> 3,14 string.Format("F:2") --> 3,15
26 июн 18, 12:11    [21521521]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Dima T
Member

Откуда:
Сообщений: 15796
double это представление с погрешностью, т.е. 2,135 может быть в реале 2.13499999999999999999999999999

используй decimal
26 июн 18, 12:20    [21521558]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
fortibransa
Member

Откуда: СПб
Сообщений: 22917
Dima T
double это представление с погрешностью, т.е. 2,135 может быть в реале 2.13499999999999999999999999999

используй decimal
Оказывается по поводу этих 2.135, чуть ли ни диссертации написаны.
26 июн 18, 12:23    [21521573]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 4206
fortibransa,

с этой проблемой борются с тех времен, как научились представлять дробные числа в виде мантиссы и экспоненты. В результате чего, у значения типа double или float всегда есть хвостик, который надо учитывать.
С этим не нужно бороться, просто нужно не забывать об этом. В том числе и то, что 2 равных на 1 взгляд числа с типом double могут оказаться далеко не одним и тем же.
26 июн 18, 13:04    [21521750]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 4206
забыл добавить ссылку на ютуб
26 июн 18, 13:05    [21521752]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
fortibransa
Member

Откуда: СПб
Сообщений: 22917
Roman Mejtes
fortibransa,

с этой проблемой борются с тех времен, как научились представлять дробные числа в виде мантиссы и экспоненты. В результате чего, у значения типа double или float всегда есть хвостик, который надо учитывать.
С этим не нужно бороться, просто нужно не забывать об этом. В том числе и то, что 2 равных на 1 взгляд числа с типом double могут оказаться далеко не одним и тем же.
Для этого в Round специально есть эта хрень MidpointRounding.AwayFromZero

Что ты мне лекции читаешь, но она на 2.135 лажает, а стринг формат нет? Мне заказчики серьезные вопросы задают, почему в логе на экране такая цифра, а сохраняется другая.
26 июн 18, 14:23    [21522069]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Dima T
Member

Откуда:
Сообщений: 15796
fortibransa
а стринг формат нет?

тоже не идеален
Double x = 2.135;
Console.WriteLine("{0} {0:F2} {1} {1:F2}", x, x-2.13);

Результат
2,135 2,14 0,00499999999999989 0,00

ИМХО Как вариант можно перед округлением делать +0.001*минимальная разрядность, т.е. прибавлять значение больше погрешности, в этом случае будет гарантия что реальное значение чуть больше.
Например если нужна точность до сотых, то
Math.Round(x + 0.00001, 2)
26 июн 18, 15:23    [21522402]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
LR
Member

Откуда: 8P8C
Сообщений: 2423
fortibransa,
в данном случае Round не виноват))

Поскольку бесконечное множество вещественных чисел отображается на конечное множество чисел диапазона того или иного типа (float/double/decimal) ошибки точности представления чисел неизбежны. Конечно, для decimal, при вдвое большем размере и меньшем диапазоне, они будут существенно меньше (незаментней) чем для double (и тем более для float).

То, что мы захардкодили double-значение 2.135 и наблюдаем его в отладчике, еще не означает что оно таковым является (для процессора). Вот с помощью этой программы IEEE754 можно посмотреть в какое реальное значение "форматируется" задаваемое.
В нашем случае точное значение 2.1349999999999997868371792719699442386627197265625

Косвенным подтверджением будут результаты в студии:
var xval = 2.135 * 1e17; // 2.1349999999999997E+17
или в отладчике браузера:
2.135 * 1e17: 213499999999999970
26 июн 18, 20:28    [21523241]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
LR
Member

Откуда: 8P8C
Сообщений: 2423
Вот на этой страничке тоже можно посмотреть "Value actually stored in float" (для double нет, но не принципиально).
26 июн 18, 20:59    [21523280]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 4206
LR
fortibransa,
в данном случае Round не виноват))

Поскольку бесконечное множество вещественных чисел отображается на конечное множество чисел диапазона того или иного типа (float/double/decimal) ошибки точности представления чисел неизбежны. Конечно, для decimal, при вдвое большем размере и меньшем диапазоне, они будут существенно меньше (незаментней) чем для double (и тем более для float).

То, что мы захардкодили double-значение 2.135 и наблюдаем его в отладчике, еще не означает что оно таковым является (для процессора). Вот с помощью этой программы IEEE754 можно посмотреть в какое реальное значение "форматируется" задаваемое.
В нашем случае точное значение 2.1349999999999997868371792719699442386627197265625

Косвенным подтверджением будут результаты в студии:
var xval = 2.135 * 1e17; // 2.1349999999999997E+17
или в отладчике браузера:
2.135 * 1e17: 213499999999999970

я кинул ссылку автору на лекцию из MIT, но он не хотел, не читать, не смотреть, думаю до него и так не дойдет. Ему просто "надо", а как, не его проблемы. Хочет заставить компьютер работать ,но при этом не хочет знать как он работает =)
27 июн 18, 00:05    [21523809]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
LR
Member

Откуда: 8P8C
Сообщений: 2423
Roman Mejtes
на лекцию из MIT

Спасибо за ссылку, чудесная лекция, потрясающий препод))

Кстати, "полагаясь на print" тоже можно было бы ухватить суть проблемы (G9/G17 - "максимальный" вывод):
System.Diagnostics.Debug.WriteLine($"2.135f={2.135f:G8}(G8)={2.135f:G9}(G9), 2.135d={2.135d:G16}(G16)={2.135d:G17}(G17)");
----------
2.135f=2.135(G8)=2.13499999(G9), 2.135d=2.135(G16)=2.1349999999999998(G17)
27 июн 18, 00:43    [21523873]     Ответить | Цитировать Сообщить модератору
 Re: Округление  [new]
fortibransa
Member

Откуда: СПб
Сообщений: 22917
Roman Mejtes
LR
fortibransa,
в данном случае Round не виноват))

Поскольку бесконечное множество вещественных чисел отображается на конечное множество чисел диапазона того или иного типа (float/double/decimal) ошибки точности представления чисел неизбежны. Конечно, для decimal, при вдвое большем размере и меньшем диапазоне, они будут существенно меньше (незаментней) чем для double (и тем более для float).

То, что мы захардкодили double-значение 2.135 и наблюдаем его в отладчике, еще не означает что оно таковым является (для процессора). Вот с помощью этой программы IEEE754 можно посмотреть в какое реальное значение "форматируется" задаваемое.
В нашем случае точное значение 2.1349999999999997868371792719699442386627197265625

Косвенным подтверджением будут результаты в студии:
var xval = 2.135 * 1e17; // 2.1349999999999997E+17
или в отладчике браузера:
2.135 * 1e17: 213499999999999970

я кинул ссылку автору на лекцию из MIT, но он не хотел, не читать, не смотреть, думаю до него и так не дойдет. Ему просто "надо", а как, не его проблемы. Хочет заставить компьютер работать ,но при этом не хочет знать как он работает =)
Родной, я знаю как он работает и без лекций того чувачка, лекции и сам могу почитать.
27 июн 18, 07:03    [21523958]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить