Проблема с double
От: sheep2k Россия  
Дата: 09.06.06 20:41
Оценка:
Hi all!

Простенький код:

using System;
using System.Collections.Generic;
using System.Text;

namespace dbl
{
    class Program
    {
        static void Main(string[] args)
        {
            double x = 20.1;
            double a = 3.5;
            double z = x * a;
            Console.WriteLine(z);
            Console.ReadKey();
        }
    }
}


В консоль выводит правильно — 70,35.

Но вот если в отладчике посмотреть значение переменной z — оно будет 70.350000000000009.
У меня все юнит-тесты слетают из-за этого
Это баг или у меня уже глюки? Подскажите, пожалуйста!

(NET 2.0, WinXP SP2, русская локаль, Visual 2005.)
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Проблема с double
От: Burd Украина http://proxysearcher.sourceforge.net
Дата: 09.06.06 20:59
Оценка: 1 (1) +1
Здравствуйте, sheep2k, Вы писали:

S>Это баг или у меня уже глюки? Подскажите, пожалуйста!


S>(NET 2.0, WinXP SP2, русская локаль, Visual 2005.)


Это не баг... Такая уж особенность типов с плавающей запятой что они не всегда возвращают точный результат до последнео знака. В последнем знаке могут появится неточности... Это именно тот случай
Любая задача имеет решение, даже когда решения не существует
Re: Проблема с double
От: Roman Rumin Россия http://www.radio-taxi.ru/
Дата: 09.06.06 22:06
Оценка: 7 (2)
Здравствуйте, sheep2k, Вы писали:

S>В консоль выводит правильно — 70,35.


S>Но вот если в отладчике посмотреть значение переменной z — оно будет 70.350000000000009.


Я накидал что-то вроде спецификации типа double 64 бит.
http://www.rsdn.ru/File/44434/Rumin_Roman_type_double.rar
(для просмотра желателен в системе шрифт Courier New с поддержкой юникод)
будут вопросы — спрашивайте

Даблы обычно считает FPU, на который и SIMD расширения навешаны.
У разных процессоров разные FPU и разные SIMD
Поэтому точность вычислений на разных процессорах может быть разной.

Минимальное число, на которое может инкриментироваться double — это эпсилон:
4,9406564584124659E-324 = ~ 0,0000000000000005E-308
на бинарном уровне +0.00 00000000 00000000 00000000 00000000 00000000 00000001 ? -00 00000000
Такси ст
Re[2]: Проблема с double
От: sheep2k Россия  
Дата: 10.06.06 06:47
Оценка:
Здравствуйте, Burd, Вы писали:

B>Это не баг... Такая уж особенность типов с плавающей запятой что они не всегда возвращают точный результат до последнео знака. В последнем знаке могут появится неточности... Это именно тот случай


А есть возможность в C# как-то ограничить точность вычислений, скажем, до второго знака после запятой?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Проблема с double
От: kon_v_palto  
Дата: 10.06.06 07:11
Оценка:
Здравствуйте, sheep2k, Вы писали:

S>Здравствуйте, Burd, Вы писали:


B>>Это не баг... Такая уж особенность типов с плавающей запятой что они не всегда возвращают точный результат до последнео знака. В последнем знаке могут появится неточности... Это именно тот случай


S>А есть возможность в C# как-то ограничить точность вычислений, скажем, до второго знака после запятой?


Похоже тебе нужен Decimal а не double.

Типы с плавоющей точкой хранятся в виде a*2^b, отсюда и косяки с присвоением десятичных значений, а потом с вычислениями, и это относится ко всем языкам а не только к C#.

А Decimal храниться в десятичном виде.
Re[4]: Проблема с double
От: sheep2k Россия  
Дата: 10.06.06 08:21
Оценка:
Здравствуйте, kon_v_palto, Вы писали:

__>Похоже тебе нужен Decimal а не double.


__>Типы с плавоющей точкой хранятся в виде a*2^b, отсюда и косяки с присвоением десятичных значений, а потом с вычислениями, и это относится ко всем языкам а не только к C#.


__>А Decimal храниться в десятичном виде.


Нужен мненно double.
Но я победил NUnit, просто невнимательно вчера посмотрел метод Assert.AreEqual(). Оказывается для сравнения double можно указать дельту.

Вообщем, моя конкретная проблема решается так:


[Test]
public void MultiplyTest()
{
    double x = 20.10;
    double a = 3.50;
    double z = x * a;
    Assert.AreEqual(70.35d, z, 0.001);
}
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Проблема с double
От: stasukas  
Дата: 13.06.06 06:53
Оценка:
Здравствуйте, sheep2k, Вы писали:

S>В консоль выводит правильно — 70,35.


S>Но вот если в отладчике посмотреть значение переменной z — оно будет 70.350000000000009.

S>У меня все юнит-тесты слетают из-за этого

Нас еще в институте учили, что в практически любом расчете есть погрешность.

При проверке результата необходимо задать коэффициент погрешности и сравнивать с ним абсолютное значение разницы проверяемых значений. Вид проверки будет примерно таким:

double x = 20.1;
double a = 3.5;

double result = x * a;
double etalon = 70,35;

double delta = 0.0000001;

if( System.Math.Abs(result - etalon) < delta )
    Console.WriteLine("Test passed");
else
    Console.WriteLine("Test failed");

Console.ReadKey();
... << RSDN@Home 1.2.0 alpha rev. 650>>
Now playing:
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.