C#
имеет decimal
тип, который используется для чисел, которые нуждаются в точном представлении в базе 10. Например, 0.1
не может быть представлен в базе 2 (например, float
и double
) и всегда будет приближенным при хранении в переменных этих типов.
Мне было интересно, возможен ли обратный факт. Существуют ли числа, которые не могут быть представлены в базе 10, но могут быть представлены в базе 2 (в этом случае я бы хотел использовать float
вместо них a decimal
для их обработки)?
c#
numbers
floating-point
Максимум
источник
источник
0.11_b2
, запишите его как0.5 + 0.5 * 0.5
. Есть ли какой-либо шаг, который может привести к неудаче или привести к повторению десятичной дроби? Лично я нахожу, что это упражнение отлично справляется с интуицией о числах с основанием 2. Я полагаю, можно пойти еще дальше и превратить это упражнение в доказательство по построению.0.0999999....998..
точное, но не полное число0.1
- аппроксимации, такие как округление до ближайшего сотого с,0.100
являются проблемой реализации, которая подразумевает не показывать вам все цифры и вместо этого округлять.Ответы:
Вот ключ к вашему затруднению:
10
является продуктом2
и5
. Вы можете представить любое число точно в десятичных десятичных числах, то есть k * 1/2 n * 1/5 m гдеk
,n
иm
являются целыми числами.Альтернативно формулируется - если число
n
в 1 / n содержит фактор, который не является частью факторов базы, число не сможет быть точно представлено в фиксированном количестве цифр в двоичном / десятичном / любом другом разложении этого номер - он будет иметь повторяющуюся часть. Например, 1/15 = 0,0666666666 .... потому что 3 (15 = 3 * 5) не в 10 раз.Таким образом, все, что может быть представлено в базе 2 точно (k * 1/2 n ), может быть точно представлено в базе 10.
Помимо этого, существует проблема того, сколько цифр / битов вы используете для представления числа. Есть некоторые числа, которые могут быть точно представлены в некоторой базе, но для этого требуется больше, чем некоторое количество цифр / бит.
В двоичном формате число 1/10, которое обычно равно 0,1 в десятичном виде, не может быть представлено как число, которое может быть представлено в фиксированном количестве битов в двоичном формате. Вместо этого число равно 0,00011001100110011 ... 2 (часть 0011 повторяется вечно).
Давайте посмотрим на число 1 2 /1010 2 немного более близко.
Это то же самое, что вы получаете, когда пытаетесь сделать длинное деление на 1/3.
1/10, когда факторинг равен 1 / (2 1 * 5 1 ). Для основания 10 (или любого кратного 10) это число заканчивается и называется обычным числом . Повторяющаяся десятичная дробь известна как повторяющаяся десятичная дробь , и те числа, которые продолжаются вечно без повторения, являются иррациональными числами.
Математика за этим углубляется в малые теоремы Ферма ... и как только вы начинаете говорить Ферма или теорема, это становится Math.SE вопрос .
Ответ - нет'.
Итак, в этот момент нам всем должно быть ясно, что каждое двоичное разложение фиксированной длины рационального числа может быть представлено как десятичное разложение фиксированной длины.
Давайте внимательнее посмотрим на десятичную в C #, которая приводит нас к десятичной с плавающей запятой в .NET и, учитывая автора, я согласен, вот как это работает.
Я сразу укажу, что из-за этой реализации есть числа в
double
типе, которые не могут быть представлены вdecimal
- те, которые находятся вне диапазона.Double.Epsilon
это то,4.94065645841247e-324
что не может быть представлено вdecimal
, но может быть вdouble
.Однако в пределах диапазона, который может представлять десятичная дробь, он обладает большей точностью, чем другие нативные типы, и может представлять их без ошибок.
Есть несколько других типов, плавающих вокруг. В C # есть BigInteger, который может представлять произвольно большое целое число. Там нет никакого эквивалента в Java BigDecimal (который может представлять числа с десятичными цифрами до 2 32 цифр длинных - что является значительным диапазон) точно . Тем не менее, если вы немного поковыряетесь, вы сможете найти ручные реализации.
Есть некоторые языки, которые также имеют рациональный тип данных, который позволяет вам точно представлять рациональные значения (так что 1/3 фактически равна 1/3).
Специально для C # и выбора числа с плавающей точкой или рационального, я буду откладывать на Jon Skeet из плавающей десятичной точки в .NET :
источник
n = 15
иb = 10
они не являются относительно простыми («не делите общих положительных факторов (делителей), кроме 1»), потому что они имеют 5 как фактор. Ключевым моментом является то, что не все факторы 15 (5 и 3) не являются также факторами 10. (Помимо: есть ли слово для обозначения чисел, которые имеют или не разделяют все общие факторы?) Я думаю, что это аккуратно завернутый в вашеk, n, m
уравнение, но чтобы действительно обернуть его вокруг, мне нужно было бы увидеть 3D-график. В любом случае, заслуженно +1 к вам.Как только вы выйдете за пределы допустимых значений, ответ будет положительным. Тем не менее, почти все внутри диапазона будет иметь представление. C # Десятичная ссылка Хотя это не указано в спецификации, иррациональные числа не могут быть точно представлены (например, e 1 , pi, квадратный корень из 2 и т. Д.).
1 Спасибо MichaelT за напоминание о другом иррациональном номере.
источник
e
(2.71 ...). Натуральный лог - ln (x) - логарифмическая база e. Таким образом, иррациональные основы существуют и полезны. В особой полезности базового числа я не уверен - но это не значит, что он где-то не используется.Тип с плавающей запятой с двумя базовыми значениями может точно представлять множество значений, которые не могут иметь тип с базовыми десятьми одинакового размера . Любое значение, которое будет точно представлено типом base-2 некоторого размера, будет точно представлено в типе base-ten достаточного размера. Требуемый размер для типа чисто базовых десяти для представления всех значений двоичного числа с плавающей запятой будет зависеть от диапазона экспонент двоичного типа; сотни битов за
float
или тысячи заdouble
.При этом
Decimal
тип является достаточно большим, чтобы его можно было использовать в качестве «универсального» типа, способного хранить значение любого другого числового примитива и обеспечивать некоторые другие дополнительные функции, кроме того (если ничего другого, использовать один бит чтобы указать, является ли сохраненное значение результатом преобразования adouble
, и если этот бит установлен, используйте 64 бита для хранения рассматриваемого значения). Однако Microsoft решила этого не делать. В результате, преобразование ,double
чтобыDecimal
не сможет полностью при больших значениях, будет вызывать малые значения должны быть округлены до ближайшего 1E-28. Кроме того, даже в динамическом диапазонеdecimal
, метод преобразования не будет "туда-обратно". Например, оценка 1.0 / 3.0 как двойного результата даст 0.3333333333333333148, но преобразование этого значения в десятичное даст 0.333333333333333m, а обратное преобразование в двойное приведет к 0.3333333333333329818.источник