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.)
Здравствуйте, sheep2k, Вы писали:
S>Это баг или у меня уже глюки? Подскажите, пожалуйста!
S>(NET 2.0, WinXP SP2, русская локаль, Visual 2005.)
Это не баг... Такая уж особенность типов с плавающей запятой что они не всегда возвращают точный результат до последнео знака. В последнем знаке могут появится неточности... Это именно тот случай
Любая задача имеет решение, даже когда решения не существует
Здравствуйте, sheep2k, Вы писали:
S>В консоль выводит правильно — 70,35.
S>Но вот если в отладчике посмотреть значение переменной z — оно будет 70.350000000000009.
Даблы обычно считает FPU, на который и SIMD расширения навешаны.
У разных процессоров разные FPU и разные SIMD
Поэтому точность вычислений на разных процессорах может быть разной.
Минимальное число, на которое может инкриментироваться double — это эпсилон:
4,9406564584124659E-324 = ~ 0,0000000000000005E-308
на бинарном уровне +0.00 00000000 00000000 00000000 00000000 00000000 00000001 ? -00 00000000
Здравствуйте, Burd, Вы писали:
B>Это не баг... Такая уж особенность типов с плавающей запятой что они не всегда возвращают точный результат до последнео знака. В последнем знаке могут появится неточности... Это именно тот случай
А есть возможность в C# как-то ограничить точность вычислений, скажем, до второго знака после запятой?
Здравствуйте, sheep2k, Вы писали:
S>Здравствуйте, Burd, Вы писали:
B>>Это не баг... Такая уж особенность типов с плавающей запятой что они не всегда возвращают точный результат до последнео знака. В последнем знаке могут появится неточности... Это именно тот случай
S>А есть возможность в C# как-то ограничить точность вычислений, скажем, до второго знака после запятой?
Похоже тебе нужен Decimal а не double.
Типы с плавоющей точкой хранятся в виде a*2^b, отсюда и косяки с присвоением десятичных значений, а потом с вычислениями, и это относится ко всем языкам а не только к C#.
Здравствуйте, 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);
}
Здравствуйте, 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: