Сравнение двойных значений в C#

#create является более короткой версией новых, и сохранить. #create! выдает исключение, если проверка не была положительна.

59
задан Vadim Ovchinnikov 15 March 2018 в 17:11
поделиться

11 ответов

Это стандартная проблема из-за того, как компьютер хранит значения с плавающей запятой. Поищите здесь "проблему с плавающей запятой", и вы найдете массу информации.

Короче говоря, float / double не может точно хранить 0.1 . Он всегда будет немного неправильным.

Вы можете попробовать использовать десятичный тип , который хранит числа в десятичной системе счисления. Таким образом, 0,1 будет точно представленным.


Вы хотели узнать причину:

Float / double хранятся как двоичные дроби, а не как десятичные дроби. Для иллюстрации:

12,34 в десятичной системе счисления (что мы используем) означает

1 * 101 + 2 * 100 + 3 * 10-1 + 4 * 10-2

Компьютер хранит числа с плавающей запятой таким же образом, за исключением того, что он использует базу 2 : 10.01 означает

1 * 21 + 0 * 20 + 0 * 2-1 + 1 * 2-2

Теперь вы, вероятно, знаете, что есть некоторые числа, которые не могут быть полностью представлены в нашей десятичной системе счисления. Например, 1/3 в десятичной системе счисления будет 0,3333333… . То же самое происходит в двоичной системе счисления, за исключением того, что числа, которые невозможно представить точно, различны. Среди них номер 1/10 . В двоичной системе счисления, то есть 0,000110011001100… .

Поскольку двоичная запись не может хранить ее точно, она сохраняется с округлением.

92
ответ дан 24 November 2019 в 18:02
поделиться

Как правило:

Двойное представление достаточно хорошо в большинстве случаев, но в некоторых ситуациях может с треском провалиться. Используйте десятичные значения, если вам нужна полная точность (как в финансовых приложениях).

Большинство проблем с двойными числами возникает не из прямого сравнения, а в результате накопления нескольких математических операций, которые экспоненциально изменяют значение из-за ошибки округления и дробные ошибки (особенно при умножении и делении).

Проверьте свою логику, если код:

x = 0.1

if (x == 0.1)

он не должен давать сбой, это слишком просто, если значение X вычисляется более сложными средствами или операциями, оно вполне возможно, что метод ToString, используемый отладчиком, использует умное округление, возможно, вы можете сделать то же самое (если это слишком рискованно, вернитесь к использованию десятичной дроби):

if (x.ToString() == "0.1")
0
ответ дан 24 November 2019 в 18:02
поделиться

Double (на некоторых языках называемый float) вызывает проблемы из-за проблем с округлением, это хорошо, только если вам нужны приблизительные значения.

Тип данных Decimal делает то, что вы хотите.

Для ссылки decimal и Decimal одинаковы в .NET C #, как и типы double и Double, они оба относятся к одному и тому же типу (хотя decimal и double очень разные, как вы уже видели).

Помните, что тип данных Decimal связан с некоторыми затратами, поэтому используйте его с осторожностью, если вы смотрите на циклы и т. д.

1
ответ дан 24 November 2019 в 18:02
поделиться

Используйте десятичное . У него нет этой «проблемы».

2
ответ дан 24 November 2019 в 18:02
поделиться

Представления чисел с плавающей запятой общеизвестно неточны (из-за способа хранения чисел с плавающей запятой), например, x может быть 0,0999999999 или 0,100000001, и ваше условие не будет выполнено. Если вы хотите определить, равны ли числа с плавающей запятой, вам необходимо указать, равны ли они в пределах определенного допуска.

т.е.

if(Math.Abs(x) - 0.1 < tol) {
   // Do something 
}
0
ответ дан 24 November 2019 в 18:02
поделиться

1) Должен ли я использовать Double или double ???

Double и double - это одно и то же. double - это просто ключевое слово C #, работающее как псевдоним для класса System.Double Чаще всего используются псевдонимы! То же самое для string ( System.String ), int ( System.Int32 )

См. Также Built- В таблице типов (справочник по C #)

1
ответ дан 24 November 2019 в 18:02
поделиться

Двойной и двойной идентичны.

Причину см. http://www.yoda.arachsys.com/csharp/floatingpoint.html . Вкратце: дубль не является точным типом, и разница в минуту между «x» и «0,1» отбросит его.

3
ответ дан 24 November 2019 в 18:02
поделиться

Из документации :

Точность в сравнении Метод Equals следует использовать с осторожностью, потому что два явно эквивалентных значения могут быть неравными из-за разной точности двух значений. В следующем примере сообщается, что значение Double .3333 и значение Double, возвращаемое путем деления 1 на 3, не равны.

...

Вместо сравнения на равенство один рекомендуемый метод включает определение допустимой разницы между двумя значениями. (например, 0,01% от одного из значений). Если абсолютное значение разницы между двумя значениями меньше или равно этому запасу, разница, вероятно, связана с различиями в точности и, следовательно, значения, вероятно, будут равны. В следующем примере этот метод используется для сравнения .33333 и 1/3, двух значений Double, которые в предыдущем примере кода оказались неравными.

Итак, если вам действительно нужно значение double, Если можете, измените его на десятичное. Это будет медленнее , но у вас не будет такой проблемы.

5
ответ дан 24 November 2019 в 18:02
поделиться

Сравнение чисел с плавающей запятой не всегда может быть выполнено точно из-за округления. Для сравнения

(x == .1)

компьютер действительно сравнивает

(x - .1) vs 0

Результат sybtraction не всегда может быть точно представлен из-за того, как числа с плавающей запятой представлены на машине. Следовательно, вы получаете ненулевое значение, и условие оценивается как false .

Чтобы преодолеть это сравнение

Math.Abs(x- .1) vs some very small threshold ( like 1E-9)
10
ответ дан 24 November 2019 в 18:02
поделиться

double и Double одинаковы ( double является псевдонимом для Double ) и могут использоваться как взаимозаменяемые. .

Проблема при сравнении двойного значения с другим значением состоит в том, что двойные значения являются приблизительными, а не точными значениями. Поэтому, когда вы устанавливаете x равным 0,1 , на самом деле он может быть сохранен как 0,100000001 или что-то в этом роде.

Вместо проверки на равенство следует убедиться, что разница меньше установленной минимальной разницы (допуска). Что-то вроде:

if (Math.Abs(x - 0.1) < 0.0000001)
{
    ...
}
41
ответ дан 24 November 2019 в 18:02
поделиться

Известно, что точное сравнение значений с плавающей запятой не всегда работает из-за округления и проблемы внутреннего представления.

Попробуйте неточное сравнение:

if (x >= 0.099 && x <= 0.101)
{
}

Другой альтернативой является использование десятичных данных тип.

3
ответ дан 24 November 2019 в 18:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: