#create является более короткой версией новых, и сохранить. #create! выдает исключение, если проверка не была положительна.
Это стандартная проблема из-за того, как компьютер хранит значения с плавающей запятой. Поищите здесь "проблему с плавающей запятой", и вы найдете массу информации.
Короче говоря, 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…
.
Поскольку двоичная запись не может хранить ее точно, она сохраняется с округлением.
Как правило:
Двойное представление достаточно хорошо в большинстве случаев, но в некоторых ситуациях может с треском провалиться. Используйте десятичные значения, если вам нужна полная точность (как в финансовых приложениях).
Большинство проблем с двойными числами возникает не из прямого сравнения, а в результате накопления нескольких математических операций, которые экспоненциально изменяют значение из-за ошибки округления и дробные ошибки (особенно при умножении и делении).
Проверьте свою логику, если код:
x = 0.1
if (x == 0.1)
он не должен давать сбой, это слишком просто, если значение X вычисляется более сложными средствами или операциями, оно вполне возможно, что метод ToString, используемый отладчиком, использует умное округление, возможно, вы можете сделать то же самое (если это слишком рискованно, вернитесь к использованию десятичной дроби):
if (x.ToString() == "0.1")
Double (на некоторых языках называемый float) вызывает проблемы из-за проблем с округлением, это хорошо, только если вам нужны приблизительные значения.
Тип данных Decimal делает то, что вы хотите.
Для ссылки decimal и Decimal одинаковы в .NET C #, как и типы double и Double, они оба относятся к одному и тому же типу (хотя decimal и double очень разные, как вы уже видели).
Помните, что тип данных Decimal связан с некоторыми затратами, поэтому используйте его с осторожностью, если вы смотрите на циклы и т. д.
Используйте десятичное
. У него нет этой «проблемы».
Представления чисел с плавающей запятой общеизвестно неточны (из-за способа хранения чисел с плавающей запятой), например, x может быть 0,0999999999 или 0,100000001, и ваше условие не будет выполнено. Если вы хотите определить, равны ли числа с плавающей запятой, вам необходимо указать, равны ли они в пределах определенного допуска.
т.е.
if(Math.Abs(x) - 0.1 < tol) {
// Do something
}
1) Должен ли я использовать Double или double ???
Double
и double
- это одно и то же. double
- это просто ключевое слово C #, работающее как псевдоним для класса System.Double
Чаще всего используются псевдонимы! То же самое для string
( System.String
), int
( System.Int32
)
Двойной и двойной идентичны.
Причину см. http://www.yoda.arachsys.com/csharp/floatingpoint.html . Вкратце: дубль не является точным типом, и разница в минуту между «x» и «0,1» отбросит его.
Точность в сравнении Метод Equals следует использовать с осторожностью, потому что два явно эквивалентных значения могут быть неравными из-за разной точности двух значений. В следующем примере сообщается, что значение Double .3333 и значение Double, возвращаемое путем деления 1 на 3, не равны.
...
Вместо сравнения на равенство один рекомендуемый метод включает определение допустимой разницы между двумя значениями. (например, 0,01% от одного из значений). Если абсолютное значение разницы между двумя значениями меньше или равно этому запасу, разница, вероятно, связана с различиями в точности и, следовательно, значения, вероятно, будут равны. В следующем примере этот метод используется для сравнения .33333 и 1/3, двух значений Double, которые в предыдущем примере кода оказались неравными.
Итак, если вам действительно нужно значение double, Если можете, измените его на десятичное. Это будет медленнее , но у вас не будет такой проблемы.
Сравнение чисел с плавающей запятой не всегда может быть выполнено точно из-за округления. Для сравнения
(x == .1)
компьютер действительно сравнивает
(x - .1) vs 0
Результат sybtraction не всегда может быть точно представлен из-за того, как числа с плавающей запятой представлены на машине. Следовательно, вы получаете ненулевое значение, и условие оценивается как false
.
Чтобы преодолеть это сравнение
Math.Abs(x- .1) vs some very small threshold ( like 1E-9)
double
и Double
одинаковы ( double
является псевдонимом для Double
) и могут использоваться как взаимозаменяемые. .
Проблема при сравнении двойного значения с другим значением состоит в том, что двойные значения являются приблизительными, а не точными значениями. Поэтому, когда вы устанавливаете x
равным 0,1
, на самом деле он может быть сохранен как 0,100000001
или что-то в этом роде.
Вместо проверки на равенство следует убедиться, что разница меньше установленной минимальной разницы (допуска). Что-то вроде:
if (Math.Abs(x - 0.1) < 0.0000001)
{
...
}
Известно, что точное сравнение значений с плавающей запятой не всегда работает из-за округления и проблемы внутреннего представления.
Попробуйте неточное сравнение:
if (x >= 0.099 && x <= 0.101)
{
}
Другой альтернативой является использование десятичных данных тип.