Double num что это

Преобразования типов и безопасность типов

В этом документе описаны распространенные проблемы преобразования типов и описывается, как избежать их использования в коде C++.

Когда компилятор обнаруживает ненадежное преобразование, он выдает ошибку или предупреждение. Произошла ошибка при остановке компиляции. Предупреждение позволяет продолжить компиляцию, но указывает на возможную ошибку в коде. Однако даже если программа компилируется без предупреждений, она по-прежнему может содержать код, который вызывает неявные преобразования типов, приводящие к неправильным результатам. Ошибки типов также могут вводиться явными преобразованиями или приведениями в коде.

Неявные преобразования типов

Если выражение содержит операнды различных встроенных типов и явные приведения отсутствуют, компилятор использует встроенные стандартные преобразования для преобразования одного из операндов, чтобы типы совпадали. Компилятор пытается выполнить преобразования в четко определенной последовательности, пока она не завершится успешно. Если выбранное преобразование является повышением, компилятор не выдает предупреждение. Если преобразование является узким, компилятор выдает предупреждение о возможной утрате данных. Происходит ли фактическая потери данных, зависит от фактических значений, но рекомендуется считать это предупреждение как ошибку. Если включен определяемый пользователем тип, компилятор пытается использовать преобразования, указанные в определении класса. Если не удается найти допустимое преобразование, компилятор выдает ошибку и не компилирует программу. Дополнительные сведения о правилах, регулирующих стандартные преобразования, см. в разделе стандартные преобразования. Дополнительные сведения о пользовательских преобразованиях см. в разделе пользовательские преобразования (C++/CLI).

Расширяющие преобразования (продвижение)

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

Сужающие преобразования (приведение)

Компилятор выполняет сужающие преобразования неявным образом, но предупреждает о возможной потере данных. Выведите эти предупреждения очень серьезно. Если вы уверены, что не произойдет потери данных, так как значения в переменной большего размера всегда помещаются в меньшую переменную, добавьте явное приведение, чтобы компилятор больше не выдавал предупреждение. Если вы не уверены, что преобразование является надежным, добавьте в код какую-либо проверку среды выполнения для обработки возможной потери данных, чтобы она не вызывала неправильные результаты.

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

В следующем примере кода показаны некоторые неявные сужающие преобразования и предупреждения, которые возникают компилятором.

Преобразования со знаком — без знака

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

Преобразования указателей

Явные преобразования (приведения)

С помощью операции приведения можно указать компилятору преобразовать значение одного типа в другой тип. В некоторых случаях компилятор вызовет ошибку, если эти два типа полностью не связаны, но в других случаях не вызывает ошибку, даже если операция не является строго типизированной. Используйте приведение с осторожностью, так как любое преобразование из одного типа в другой является потенциальным источником ошибок программы. Однако иногда требуется выполнить приведения, а не все приведения являются опасными. Одно эффективное использование приведения заключается в том, что в коде выполняется понижающие преобразования и известно, что преобразование не приводит к созданию неверных результатов в программе. Фактически, это говорит компилятору о том, что вы делаете, а также о том, что вы выполняете предупреждения. Другой способ заключается в приведении из класса указателя на класс, производный от указатель на базовый. Другой способ — приведение к переменной постоянной, чтобы передать ее в функцию, для которой требуется аргумент, не являющийся константой. Большинство этих операций приведения к некоторым рискам требует определенного риска.

В программировании в стиле C для всех типов приведений используется один и тот же оператор приведения в стиле C.

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

Дополнительные сведения см. в разделе reinterpret_cast оператор.

Источник

Double Структура

Определение

Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

Представляет число двойной точности с плавающей запятой.

Примеры

В следующем примере кода показано использование Double :

Комментарии

Floating-Point представление и точность

DoubleТип данных хранит значения с плавающей запятой двойной точности в 64-разрядном двоичном формате, как показано в следующей таблице.

ОтделениеBits
Значащим или мантисса0-51
Показатель степени52-62
Знак (0 = положительный, 1 = отрицательный)63

Точно так же, как десятичные дроби не могут точно представлять некоторые дробные значения (например, 1/3 или Math.PI ), двоичные дроби не могут представлять некоторые дробные значения. Например, 1/10, которая точно представляется в виде десятичной дроби, представляется в виде. 001100110011 в виде двоичной дроби с шаблоном «0011», повторяющимся до бесконечности. В этом случае значение с плавающей запятой обеспечивает неточное представление числа, которое оно представляет. Выполнение дополнительных математических операций с исходным значением с плавающей запятой часто приводит к увеличению нехватки точности. Например, если сравнить результат умножения на 10, а затем увеличить значение от 0,1 до. 1 9 раз, мы видим, что это сложение, так как оно включало восемь дополнительных операций, создало менее точный результат. Обратите внимание, что это различие очевидно только в том случае, если мы отображаем два Double значения с помощью строки стандартного числового форматаR, которая при необходимости отображает все 17 знаков точности, поддерживаемые Double типом.

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

Ограниченная точность числа с плавающей запятой имеет несколько последствий:

Два числа с плавающей запятой, которые могут казаться равными при определенной точности, на самом деле отличаются, поскольку их менее значащие цифры различаются. В следующем примере ряд чисел добавляется вместе, а их итог сравнивается с ожидаемым итогом. Хотя два значения выглядят одинаково, вызов Equals метода указывает, что они не являются.

Если изменить элементы форматирования в Console.WriteLine(String, Object, Object) инструкции с <0>и <1>на <0:R>и, <1:R>чтобы отобразить все значащие цифры двух Double значений, то ясно, что эти два значения не равны из-за потери точности во время операций сложения. В этом случае проблему можно устранить, вызвав Math.Round(Double, Int32) метод, чтобы округлить Double значения до нужной точности перед выполнением сравнения.

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

Если точность числовых операций с дробными значениями важна, можно использовать Decimal вместо Double типа. Если точность числовых операций с целочисленными значениями вне диапазона Int64 UInt64 типов или важна, используйте BigInteger тип.

Значение может не циклически передавалться, если используется число с плавающей запятой. Значение считается циклическим, если операция преобразует исходное число с плавающей запятой в другую форму, операция обратного преобразования преобразует преобразованную форму обратно в число с плавающей запятой, а окончательное число с плавающей запятой не равно исходному числу с плавающей запятой. Цикл обработки может завершиться ошибкой, поскольку одна или несколько наименьших значащих цифр теряются или изменяются при преобразовании. В следующем примере три Double значения преобразуются в строки и сохраняются в файле. Как видно из выходных данных, несмотря на то, что значения выглядят идентичными, восстановленные значения не равны исходным значениям.

В этом случае можно успешно выполнить циклический обмен значениями, используя стандартную строку числового формата «G17» для сохранения полной точности Double значений, как показано в следующем примере.

При использовании со Double значением описатель формата R в некоторых случаях не может успешно выполнить циклический обмен исходным значением. Чтобы обеспечить Double успешный циклический обмен значениями, используйте описатель формата «G17».

Чтобы избежать этой проблемы, используйте либо Double вместо Single типа данных, либо используйте Round метод, чтобы оба значения имели одинаковую точность.

Проверка на равенство

Чтобы считаться равными, два Double значения должны представлять одинаковые значения. Однако из-за различий в точности между значениями или из-за потери точности на одно или оба значения значения с плавающей запятой, которые должны быть одинаковыми, часто становятся неравными из-за различий в их минимально значащих цифрах. В результате вызовы Equals метода для определения того, равны ли два значения, или вызовы CompareTo метода для определения связи между двумя Double значениями, часто дают непредвиденные результаты. Это очевидно в следующем примере, где два очевидных значения могут Double быть неравными, так как первая имеет 15 разрядов точности, а вторая — 17.

В случаях, когда вероятность потери точности может повлиять на результат сравнения, можно принять любые из следующих альтернатив для вызова Equals CompareTo метода или:

Вызовите Math.Round метод, чтобы убедиться, что оба значения имеют одинаковую точность. Следующий пример изменяет предыдущий пример, чтобы использовать этот подход, чтобы два дробных значения были эквивалентными.

Проблема точности по-прежнему применима к округлению средних значений. Дополнительные сведения см. в описании метода Math.Round(Double, Int32, MidpointRounding).

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

Double.Epsilon иногда используется в качестве абсолютной меры расстояния между двумя Double значениями при проверке на равенство. Однако Double.Epsilon измеряет наименьшее возможное значение, которое можно добавить или вычесть из, Double значение которого равно нулю. Для большинства положительных и отрицательных Double значений значение Double.Epsilon слишком мало для обнаружения. Таким образом, за исключением нулевых значений, не рекомендуется использовать его в тестах на равенство.

В следующем примере используется второй подход для определения IsApproximatelyEqual метода, который проверяет относительное различие между двумя значениями. Он также отличается от результата вызовов IsApproximatelyEqual метода и Equals(Double) метода.

Floating-Point значения и исключения

В отличие от операций с целочисленными типами, которые создают исключения в случае переполнения или недопустимых операций, таких как деление на ноль, операции с значениями с плавающей запятой не создают исключения. Вместо этого в исключительных ситуациях результат операции с плавающей запятой равен нулю, плюс бесконечность, отрицательная бесконечность или не является числом (NaN):

Если результат операции с плавающей запятой слишком мал для конечного формата, результат равен нулю. Это может произойти при умножении двух очень маленьких чисел, как показано в следующем примере.

PositiveInfinity также результаты из деления на ноль с положительным делимым и NegativeInfinity результатом деления на ноль с отрицательным делимым.

Преобразования типов и двойная структура

В Double структуре не определены явные или неявные операторы преобразования. вместо этого преобразования реализуются компилятором.

Обратите внимание, что преобразование значения некоторых числовых типов в Double значение может привести к утрате точности. Как показано в примере, возможна утрата точности при преобразовании Decimal значений, Int64 и UInt64 в Double значения.

Тип результирующего значенияРезультат
Любой целочисленный типOverflowExceptionИсключение, если преобразование происходит в проверяемом контексте.

Если преобразование происходит в непроверяемом контексте (по умолчанию в C#), операция преобразования выполняется успешно, но значение переполняется.

DecimalИсключение OverflowException.
SingleSingle.NegativeInfinity для отрицательных значений.

Single.PositiveInfinity для положительных значений.

Обратите внимание, что при преобразовании Double значения в другой числовой тип может произойти утрата точности. в случае преобразования в любой из целочисленных типов, как показано в выходных данных примера, дробный компонент теряется, когда Double значение округляется (как в Visual Basic) или усекается (как в C#). Для преобразований Decimal в Single значения и Double значение может не иметь точного представления в целевом типе данных.

В следующем примере число значений преобразуется Double в несколько других числовых типов. преобразования выполняются в проверяемом контексте в Visual Basic (по умолчанию) и в C# (из-за ключевого слова checked ). Выходные данные в примере показывают результат для преобразований в проверяемом непроверяемом контексте. вы можете выполнять преобразования в непроверенном контексте в Visual Basic путем компиляции с помощью /removeintchecks+ параметра компилятора и в C#, закомментируя checked инструкцию.

Floating-Point функциональности

DoubleСтруктура и связанные типы предоставляют методы для выполнения операций в следующих областях:

IsNaN IsInfinity IsPositiveInfinity IsNegativeInfinity Для проверки этих специальных значений можно также вызвать методы,, и.

Можно также манипулировать отдельными битами Double значения. BitConverter.DoubleToInt64BitsМетод сохраняет Double битовый шаблон значения в 64-разрядном целом число. BitConverter.GetBytes(Double)Метод возвращает свой битовый шаблон в массиве байтов.

Округление. Округление часто используется как метод снижения влияния различий между значениями, вызванными проблемами представления и точности с плавающей запятой. Можно округлить Double значение, вызвав Math.Round метод.

Однако преобразование Int64 Single значений и может привести к утрате точности. В следующей таблице перечислены различия в точности для каждого из этих типов:

TypeМаксимальная точностьВнутренняя точность
Double1517
Int6419 десятичных знаков19 десятичных знаков
Single7 десятичных знаков9 десятичных знаков

Представляет наименьшее положительное значение Double больше нуля. Это поле является константой.

Представляет наибольшее возможное значение типа Double. Это поле является константой.

Представляет минимально допустимое значение типа Double. Это поле является константой.

Представляет значение, не являющееся числом ( NaN ). Это поле является константой.

Представляет минус бесконечность. Это поле является константой.

Представляет плюс бесконечность. Это поле является константой.

Методы

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

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

Возвращает значение, позволяющее определить, представляют ли этот экземпляр и заданный объект Double одно и то же значение.

Возвращает значение, показывающее, равен ли данный экземпляр заданному объекту.

Возвращает хэш-код данного экземпляра.

Возвращает TypeCode для типа значения Double.

Определяет, является ли указанное значение конечным (нулевым, поднормальным или нормальным).

Возвращает значение, позволяющее определить, равно ли данное число плюс или минус бесконечности.

Возвращает значение, показывающее, что указанное значение не является числом (NaN).

Определяет, является ли заданное значение отрицательным.

Возвращает значение, позволяющее определить, равно ли данное число минус бесконечности.

Определяет, является ли заданное значение нормальным.

Возвращает значение, показывающее, равно ли данное число плюс бесконечности.

Определяет, является ли заданное значение поднормальным.

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

Преобразует строковое представление числа в эквивалентное ему число двойной точности с плавающей запятой.

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

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

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

Преобразует числовое значение данного экземпляра в эквивалентное ему строковое представление.

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

Преобразует числовое значение данного экземпляра в эквивалентное строковое представление с использованием указанного формата.

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

Пытается отформатировать значение текущего двойного экземпляра в указанный диапазон символов.

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

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

Преобразует строковое представление числа в эквивалентное ему число двойной точности с плавающей запятой. Возвращает значение, указывающее, успешно ли выполнено преобразование.

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

Операторы

Возвращает значение, указывающее, равны ли два заданных значения Double.

Возвращает значение, указывающее, действительно ли заданное значение Double больше другого заданного значения Double.

Возвращает значение, указывающее, действительно ли заданное значение Double больше или равно другому заданному значению Double.

Возвращает значение, указывающее, не равны ли два заданных значения Double.

Возвращает значение, указывающее, действительно ли заданное значение Double меньше другого заданного значения Double.

Возвращает значение, указывающее, действительно ли заданное значение Double меньше или равно другому заданному значению Double.

Явные реализации интерфейса

Сравнивает текущий экземпляр с другим объектом того же типа и возвращает целое число, которое показывает, расположен ли текущий экземпляр перед, после или на той же позиции в порядке сортировки, что и другой объект.

Возвращает TypeCode для этого экземпляра.

Описание этого члена см. в разделе ToBoolean(IFormatProvider).

Описание этого члена см. в разделе ToByte(IFormatProvider).

Это преобразование не поддерживается. При попытке использовать этот метод выбрасывается исключение InvalidCastException.

Это преобразование не поддерживается. При попытке использовать этот метод выбрасывается исключение InvalidCastException.

Описание этого члена см. в разделе ToDecimal(IFormatProvider).

Описание этого члена см. в разделе ToDouble(IFormatProvider).

Описание этого члена см. в разделе ToInt16(IFormatProvider).

Описание этого члена см. в разделе ToInt32(IFormatProvider).

Описание этого члена см. в разделе ToInt64(IFormatProvider).

Описание этого члена см. в разделе ToSByte(IFormatProvider).

Описание этого члена см. в разделе ToSingle(IFormatProvider).

Описание этого члена см. в разделе ToType(Type, IFormatProvider).

Описание этого члена см. в разделе ToUInt16(IFormatProvider).

Описание этого члена см. в разделе ToUInt32(IFormatProvider).

Описание этого члена см. в разделе ToUInt64(IFormatProvider).

Применяется к

Потокобезопасность

Все члены этого типа являются потокобезопасными. Члены, которые могут изменить состояние экземпляра, в действительности возвращают новый экземпляр, инициализированный новым значением. Как с любым другим типом, чтение и запись общей переменной, которая содержит экземпляр этого типа, должны быть защищены блокировкой для обеспечения потокобезопасности.

Источник

Потеря точности из Double во Float или «Куда пропадали копейки?»

Преобразование чисел из одного типа в другой обычно ведется таким образом, чтобы не потерять лишних чисел, т.е. из меньшего типа к более вместительному. Но что, если предыдущий разрабочик использовал конвертацию из Double во Float и стали пропадать копейки в отчетах?
В статье приводится изучение конвертации плавающих чисел в Java:

Давайте разберемся, к чему приводит такое преобразование и почему все происходит именно так. Ведь казалось бы, раз используемые в проекте числа далеки от максимальных значений типов float и double, то конвертация его из первого во второй не должна повлечь за собой отрицательных последствий в большинстве случаев.

Любые мысли лучше подкреплять конкретными примерами, поэтому сразу же код, который родился сначала на дрожжах реальных цифр, но потом, под влиянием дискуссии на stackoverflow о подобной конвертации, он превратился в нечто более интригующее.

Способ конвертации

Для демонстрации того, что разнообразные конструкции одинаково конвертируют double во float, добавим разнообразные способы и сравним результаты:

Как можно убедиться, выражения «new Float(d)» и «(float) d» дают одинаковый результат, т.к. первое использует второе:

Если разбираться с функцией Float.parseFloat, то она отсылает нас через несколько других функций до следующей строки:

Которая точно таким же образом конвертирует double-переменную во float.
Таким образом, мы убедились, что, по крайней мере, в openjdk наиболее очевидные пути преобразования double во float сводятся к одной конструкции:

Форматы хранения float и double

В каждом примере мы вызывали функции Long.toBinaryString для Double и Integer.toBinaryString для Float, чтобы продемонстрировать форматы низкоуровневого хранения созданных переменных. Прекрасная статья об этом уже была написана (Что нужно знать про арифметику с плавающей запятой, которая стала отличным переводом английской вики, где хорошо рассказано и про двойную точность), поэтому здесь мы рассмотрим только то, касается округления.
Представленные выше программы вернули следующие результаты:

Тип double занимает 64 бита, а тип float 32, но мы видим 63 и 31 знак — это издержка реализации вывода, который заканчивается, когда остаются только нули. Следовательно, эти числа должны выглядеть так:

и 1.011010110010001011111112*2 21 — 23 =2974815.75

Таким образом, отсекая от двоичного 0110 1011 0010 0010 1111 1110 0011 1101 0111 0000 1010 0011 1101 из double последние 29 цифр, мы получаем 011 0101 1001 0001 0111 1111 во float, которое дает нам несколько другое число.

Вывод

Таким образом, конвертация из формата большей точности может привести к нетривиальным потерям достоверности используемых чисел. Что же касается непосредственно Java, то в ней лучше использовать тип Double, т.к. работа с Float чревата конвертациями из Double с потерями. А для хранения денег использовать BigDecimal, чтобы не терять копейки.

CUSTOMER SUBMITTED WORKAROUND:
Avoiding direct String-to-float conversion by using intermediate doubles.

Предложенные решения

Думаю, решение повлечет за собой другие ошибки/особенности, хотя имеет право на жизнь.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *