Здравствуйте, zbanned, Вы писали: Z>Как уже сказали на 4 сообщения выше — ошибка из-за преобразования и я это сразу же понял после первого поста. Z>Я уже два раза преобразовал и в двоичном виде, и в десятичном, все равно не нашел момента где у нас теряется эта маленькая величина. Если мы разложим 0,9 как aq^n при q = 2 то у нас может быть только два варианта: Z>0,9 ~= 9*2^-3 = 9/8 = 1,125 Z>или Z>0,9 ~= 9*2^-4 = 9/16 = 0,5625 Z>Ни один из них не дает нам ни первоначальный 0.9, ни сишный 0,8999999.
Z>Помогите правильно преобразовать 0,9 в формат с плавающей запятой, я был бы очень рад.
Хорошо. Поясню на примере. gandjustas уже написал один пример, но нас учили немного по другому переводить число в двоичное, поэтому это может будет кому интересно (хотя нас этому учили на информатике в школе).
число 9 = 1001 (это надеюсь понятно)
число 0.9 НЕ РАВНО 0.1001
Нас учили так преобразовывать дроби:
1. берем число от 0 до 1.
2. умножаем его на два.
3. если число больше еденицы, то вычитаем еденицу (в результате опять получится число 0..1). И записываем 1 как i-тую цифру после запятой двоичного числа.
4. если число после умножение меньше еденицы, то ничего не делаем. И записываем 0 как i-тую цифру после запятой двоичного числа.
5. повторяем шаги 2-4 пока в результате не получится ноль.
получаем двоичное число 0.111001.....
Это можно продолжаться до бесконечности, а мантисса у нас ограничена. отсюда и появляется погрешность. чем больше двоичное число будет содержать разрядов после запятой (а это определяется разрядностью мантиссы), тем меньше будет погрешность.
К примеру, число 0.75 сводится в ноль за 2 шага и в двоичном виде будет выглядеть как 0.11. Поэтому оно не будет иметь погрешность при преобразовании.
Здравствуйте, GGoga, Вы писали:
GG>Здравствуйте, Niswn, Вы писали:
N>>Хорошо. Поясню на примере. ... нас учили немного по другому переводить число в двоичное, поэтому это может будет кому интересно (хотя нас этому учили на информатике в школе). N>>...
GG>А как по такой схеме перевести его обратно?
Да как и с целыми числами, только степень у двойки пойдет в отрицательную область.
^ — знак степени.
Для целых:
Return Value
value rounded to the nearest 16-bit signed integer. If value is halfway between two whole numbers, the even number is returned; that is, 4.5 is converted to 4, and 5.5 is converted to 6.
В то время как явное приведение типов через (int) возвращает ближайшее целое, меньшее, чем результат. А что касается внутреннего представления float, то никто не гарантирует, что 0.9f в памяти не хранится как 0.899999. Отсюда и проблемы с преобразованием.
"Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете". (с) Макконнелл, "Совершенный код".
Здравствуйте, zbanned, Вы писали:
Z>Как уже сказали на 4 сообщения выше — ошибка из-за преобразования и я это сразу же понял после первого поста. Z>Я уже два раза преобразовал и в двоичном виде, и в десятичном, все равно не нашел момента где у нас теряется эта маленькая величина. Если мы разложим 0,9 как aq^n при q = 2 то у нас может быть только два варианта: Z>0,9 ~= 9*2^-3 = 9/8 = 1,125 Z>или Z>0,9 ~= 9*2^-4 = 9/16 = 0,5625 Z>Ни один из них не дает нам ни первоначальный 0.9, ни сишный 0,8999999.
Какую-то ересь написал.
Z>Помогите правильно преобразовать 0,9 в формат с плавающей запятой, я был бы очень рад.
Мантисса вещественных чисел хранятся как разложение по 2^(-n).
0.9 — 2^(-1) = 0.9-0.5 = 0.4 в результат уходит 1
0.4 — 2^(-2) = 0.4 — 0.25 = 0.15 в результат уходит 1
0.15 — 2^(-3) = 0.15 — 0.125 = 0.025 в результат уходит 1
0.025 < 2^(-4) в результат уходит 0
0.025 < 2^(-5) в результат уходит 0
0.025 — 2^(-6) = 0.025 — 0.015625 = 0.009375 в результат уходит 1
...
Так можно продолжать долго, результат не станет нулевым. Тем не менее бит на мантиссу у нас ограниченное количество, поэтому возникают ошибки представления чисел с плавающей точкой и 0.9 на самом деле равно 0.89999999
Здравствуйте, Niswn, Вы писали:
N>Да как и с целыми числами, только степень у двойки пойдет в отрицательную область. N>^ — знак степени. N>Для целых: N>
Если заглянуть вглубь, то как представлена константа в формате IEEE c плавающей точкой?
Когда мы пишем 0.9 = то мантисса = 899999976158142 и запятая помещается после первого разряда?
Тогда почему бы мантиссу не представить как 9? Ведь все можно проще сделать? Откуда погрешность возникает?
Z>>Тогда почему бы мантиссу не представить как 9? Ведь все можно проще сделать? Откуда погрешность возникает?
Мантисса не может быть "представлена как 9", т.к. она хранится в нормализованном виде, т.е. для чисел с плавающей запятой (в десятичном представлении): 0.5 <= Мантисса < 1.0. И вот из-за неточного представления десятичных дробей в двоичном коде и появляется погрешность.
Здравствуйте, Овощ, Вы писали:
Z>>>Тогда почему бы мантиссу не представить как 9? Ведь все можно проще сделать? Откуда погрешность возникает?
О>Мантисса не может быть "представлена как 9", т.к. она хранится в нормализованном виде, т.е. для чисел с плавающей запятой (в десятичном представлении): 0.5 <= Мантисса < 1.0. И вот из-за неточного представления десятичных дробей в двоичном коде и появляется погрешность.
Все равно не понял.
0.9 представим как a*(q^n)
а = мантисса = 9
q = система счисления = множитель = 10
n = показатель степени = -1
Итого: 0,9=9*10^-1
Откуда погрешность?
Если у нас число с плавающей запятой, то
— мантиссу 9 представим в двоичном виде как 1001
— множитель 10 = 1010
— степень -1 = 1111...11 (кол-во 1-ц в зависимости от разрядности)
Все это можно упаковать в 32 битное число с плавающей запятой без погрешности.
Здравствуйте, zbanned, Вы писали:
Z>Здравствуйте, Овощ, Вы писали:
Z>>>>Тогда почему бы мантиссу не представить как 9? Ведь все можно проще сделать? Откуда погрешность возникает?
О>>Мантисса не может быть "представлена как 9", т.к. она хранится в нормализованном виде, т.е. для чисел с плавающей запятой (в десятичном представлении): 0.5 <= Мантисса < 1.0. И вот из-за неточного представления десятичных дробей в двоичном коде и появляется погрешность.
Z>Все равно не понял. Z>0.9 представим как a*(q^n) Z>а = мантисса = 9 Z>q = система счисления = множитель = 10 Z>n = показатель степени = -1 Z>Итого: 0,9=9*10^-1 Z>Откуда погрешность? Z>Если у нас число с плавающей запятой, то Z>- мантиссу 9 представим в двоичном виде как 1001 Z>- множитель 10 = 1010 Z>- степень -1 = 1111...11 (кол-во 1-ц в зависимости от разрядности) Z>Все это можно упаковать в 32 битное число с плавающей запятой без погрешности.
Z>Поясните, где не прав?
А ты распиши также число 9,346242 и поймешь в чем неправ.
Здравствуйте, zbanned, Вы писали:
Z>Ок. Давай пока по проще. Хорошо, возмем q=2. Тогда получается большая погрешность: Z>0,9 ~= 9*2^-3 = 9/8 = 1,125 Z>или Z>0,9 ~= 9*2^-4 = 9/16 = 0,5625
Z>Откуда тогда берется 0,8999999?
Как уже было замечено эта погрешность происходит из-за преобразования чисел. Она заключается в том, что число 0.9 в компьютере хранится в двоичном виде, а не в десятичном, а вводишь ты его в десятичном. Попробуй преобразовать число 0.9 в двоичный вид, затем преобразовать обратно в десятичный, и ты увидишь, что это итоговое число будет близко к 0.9, но оно не будет ему равно, и величина этой погрешности зависит от количества знаков, которое занимает мантисса: чем больше разрядность мантиссы, тем меньше погрешность.
Здравствуйте, Niswn, Вы писали:
N>Здравствуйте, zbanned, Вы писали:
Z>>Ок. Давай пока по проще. Хорошо, возмем q=2. Тогда получается большая погрешность: Z>>0,9 ~= 9*2^-3 = 9/8 = 1,125 Z>>или Z>>0,9 ~= 9*2^-4 = 9/16 = 0,5625
Z>>Откуда тогда берется 0,8999999?
N>Как уже было замечено эта погрешность происходит из-за преобразования чисел. Она заключается в том, что число 0.9 в компьютере хранится в двоичном виде, а не в десятичном, а вводишь ты его в десятичном. Попробуй преобразовать число 0.9 в двоичный вид, затем преобразовать обратно в десятичный, и ты увидишь, что это итоговое число будет близко к 0.9, но оно не будет ему равно, и величина этой погрешности зависит от количества знаков, которое занимает мантисса: чем больше разрядность мантиссы, тем меньше погрешность.
Как уже сказали на 4 сообщения выше — ошибка из-за преобразования и я это сразу же понял после первого поста.
Я уже два раза преобразовал и в двоичном виде, и в десятичном, все равно не нашел момента где у нас теряется эта маленькая величина. Если мы разложим 0,9 как aq^n при q = 2 то у нас может быть только два варианта:
0,9 ~= 9*2^-3 = 9/8 = 1,125
или
0,9 ~= 9*2^-4 = 9/16 = 0,5625
Ни один из них не дает нам ни первоначальный 0.9, ни сишный 0,8999999.
Помогите правильно преобразовать 0,9 в формат с плавающей запятой, я был бы очень рад.
Народ, спасибо всем огромное за ответы! Все дошло до меня
Один вопрос остался: почему пошли именно таким путем деления? Почему бы не представить мантиссу 9 просто как 1001 (без деления)?
Т.е. можно же 32 битное число для плавающей запятой, просто разделить на две части на 16 и 16 бит и упаковать туда мантиссу со степенью, например так:
16 бит под мантиссу (знаковое 16-битное целое);
16 бит под степень (тоже знаковое 16-битное целое);
В итоге можно 0.9 представилось бы как
0000 0000 0000 1001 под мантиссу и
1111 1111 1111 1111 под степень в двоичном виде.
А число 9 представилось бы как:
0000 0000 0000 1001 под мантиссу и
0000 0000 0000 0000 под степень в двоичном виде.
И все считать по основанию 10ой системы. Для чего понадобилось таким хитрым способом переводить мантиссу делением?
Здравствуйте, zbanned, Вы писали:
Z>Один вопрос остался: почему пошли именно таким путем деления? Почему бы не представить мантиссу 9 просто как 1001 (без деления)?
Аппаратная арифметика при чисто двоичном представлении проще. В 85 году, когда был выпущен IEEE 754, это было крайне важно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1095 on Windows Vista 6.0.6001.65536>>
Здравствуйте, zbanned, Вы писали:
Z>Один вопрос остался: почему пошли именно таким путем деления? Почему бы не представить мантиссу 9 просто как 1001 (без деления)? Z>Т.е. можно же 32 битное число для плавающей запятой, просто разделить на две части на 16 и 16 бит и упаковать туда мантиссу со степенью, например так: Z>16 бит под мантиссу (знаковое 16-битное целое); Z>16 бит под степень (тоже знаковое 16-битное целое);
Z>В итоге можно 0.9 представилось бы как Z>0000 0000 0000 1001 под мантиссу и Z>1111 1111 1111 1111 под степень в двоичном виде.
Z>А число 9 представилось бы как: Z>0000 0000 0000 1001 под мантиссу и Z>0000 0000 0000 0000 под степень в двоичном виде.
И получили бы точность в 5 десятичных знаков. Сейчас бы еще больше плевались при таком раскладе.
Более того, такое кодирование избычно. Позволяет записать одно и тоже число несколькими способами, следовательно диапазон значений меньше.
Z>И все считать по основанию 10ой системы. Для чего понадобилось таким хитрым способом переводить мантиссу делением?
1)Однозначность хранимого числа
2)Оптимальность хранения
3)Быстродействие арифметических операций
Здравствуйте, zbanned, Вы писали:
Z>Один вопрос остался: почему пошли именно таким путем деления? Почему бы не представить мантиссу 9 просто как 1001 (без деления)? Z>Т.е. можно же 32 битное число для плавающей запятой, просто разделить на две части на 16 и 16 бит и упаковать туда мантиссу со степенью, например так: Z>16 бит под мантиссу (знаковое 16-битное целое); Z>16 бит под степень (тоже знаковое 16-битное целое);
Z>В итоге можно 0.9 представилось бы как Z>0000 0000 0000 1001 под мантиссу и Z>1111 1111 1111 1111 под степень в двоичном виде.
Z>А число 9 представилось бы как: Z>0000 0000 0000 1001 под мантиссу и Z>0000 0000 0000 0000 под степень в двоичном виде.
Z>И все считать по основанию 10ой системы. Для чего понадобилось таким хитрым способом переводить мантиссу делением?
A decimal number is a floating-point value that consists of a sign, a numeric value where each digit in the value ranges from 0 to 9, and a scaling factor that indicates the position of a floating decimal point that separates the integral and fractional parts of the numeric value.
The binary representation of a Decimal value consists of a 1-bit sign, a 96-bit integer number, and a scaling factor used to divide the 96-bit integer and specify what portion of it is a decimal fraction. The scaling factor is implicitly the number 10, raised to an exponent ranging from 0 to 28. Therefore, the binary representation of a Decimal value is of the form, ((-2^96 to 2^96) / 10^(0 to 28)), where -2^96-1 is equal to MinValue, and 2^96-1 is equal to MaxValue.
Здравствуйте, Niswn, Вы писали:
N>Хорошо. Поясню на примере. ... нас учили немного по другому переводить число в двоичное, поэтому это может будет кому интересно (хотя нас этому учили на информатике в школе). N>...
Не совсем понял, на каком этапе проходит округление (потеря значащего куска)?
Ведь мы теряем значащие цифры в мантиссе когда представляем float число верно?
Т.е. мы представляем 0.9f и оно кодируется во флоат итерационным делением мантиссы на два как я понял. Все здорово, но почему тогда
Console.WriteLine("{0}", 0.9f); не выводит нам 8.99999976158142, а выводит 0.9? Почему нет потерь здесь при представлении float'a?
Здравствуйте, PaulMinelly, Вы писали:
PM>Console.WriteLine("{0}", 0.9f); не выводит нам 8.99999976158142, а выводит 0.9? Почему нет потерь здесь при представлении float'a?
Здравствуйте, Ziaw, Вы писали:
Z>Здравствуйте, PaulMinelly, Вы писали:
PM>>Console.WriteLine("{0}", 0.9f); не выводит нам 8.99999976158142, а выводит 0.9? Почему нет потерь здесь при представлении float'a?
Z>В примере все дело в конвертации в double, Z>
Z>Console.WriteLine("{0}", (double)0.9f);
Z>
Z>выведет 0,899999976158142
То есть это у дабла манитсса сохраняется делением по полам, а не у флоата? И есть константа какая-нибудь для double чтобы сразу писать вроде:
Console.WriteLine("{0}", 0.9d); // чтобы выводило 0,899999976158142
Здравствуйте, PaulMinelly, Вы писали:
PM>То есть это у дабла манитсса сохраняется делением по полам, а не у флоата? И есть константа какая-нибудь для double чтобы сразу писать вроде: PM>Console.WriteLine("{0}", 0.9d); // чтобы выводило 0,899999976158142
0.9 без постфикса уже double, дополнительных указаний не требуется.
потеря происходит при конвертации 0.9f в double.
0.9 != (double)0.9f
Z>>выведет 0,899999976158142
PM>То есть это у дабла манитсса сохраняется делением по полам, а не у флоата? И есть константа какая-нибудь для double чтобы сразу писать вроде: PM>Console.WriteLine("{0}", 0.9d); // чтобы выводило 0,899999976158142
Нашел:
Console.WriteLine("{0}", 0.9D); //returns 0.9
все равно выводит 0.9
Не понятно на каком участке теряются числа. Т.е. почему при выводе 0.9 double — не происходит потеря, при выводе 0.9 float тоже не происходит, а при конвертации из флоата в дабл происходит?
PM>>То есть это у дабла манитсса сохраняется делением по полам, а не у флоата? И есть константа какая-нибудь для double чтобы сразу писать вроде: PM>>Console.WriteLine("{0}", 0.9d); // чтобы выводило 0,899999976158142 Z>0.9 без постфикса уже double, дополнительных указаний не требуется. Z>потеря происходит при конвертации 0.9f в double. Z>0.9 != (double)0.9f
Почему так происходит?
Ведь
0.9 == 0.9f
0.9 == 0.9D
0.9 != (double)0.9f
Из-за того что считывается странным образом константа при конвертации? Ведь 0.9 == 0.9f и 0.9 == 0.9D, почему 0.9 != (double)0.9f?
Как это увязать с кодировкой мантиссы итерационным делением на два? Ведь в дабл 0.9 == 0.9D все нормально кодируется и во флоат тоже? Почему потеря только при конвертации происходит?
Здравствуйте, PaulMinelly.
PM>То есть это у дабла манитсса сохраняется делением по полам, а не у флоата? И есть константа какая-нибудь для double чтобы сразу писать вроде: PM>Console.WriteLine("{0}", 0.9d); // чтобы выводило 0,899999976158142
Неа, принципы представления числа для float'а и doubl'a — в общем одинаковы. Разница в том, что сам размер дабла больше (float — 4 байта, double — 8 байтов) и, соответственно, в дабле размерность в битах полей мантиссы и экспоненты больше. Однако в обоих этих типах число 0.9 не может быть представлено точно (хотя в типе Decimal оно может быть представлено точно).
Вот пример:
float f = 0.9f;
double d = 0.9d;
decimal m = 0.9m;
// вариант 1
Console.WriteLine(f);
Console.WriteLine(d);
Console.WriteLine(m);
// вариант 2
Console.WriteLine("{0:E20}", f);
Console.WriteLine("{0:E20}", d);
Console.WriteLine("{0:E40}", m);
Я думаю, что такое поведение (разница между первым и вторым вариантом) можно объяснить тем, что в фунции WriteLine (вариант 1) формат отображения числа с плавающей точкой, принимаемый по умолчанию, подразумевает округление этого числа (до скольких-то значащих цифр) именно при выводе на консоль. Когда же мы во втором варианте явно указываем формат, то здесь отображаются все знаки в соответствии с форматом — видно, что ни float ни double точно десятичное число не представлют, хотя значение в double более точно, чем во float. Значение же в Decimal — в точности равно 0.9.
Здравствуйте, PaulMinelly, Вы писали:
PM>>>То есть это у дабла манитсса сохраняется делением по полам, а не у флоата? И есть константа какая-нибудь для double чтобы сразу писать вроде: PM>>>Console.WriteLine("{0}", 0.9d); // чтобы выводило 0,899999976158142 Z>>0.9 без постфикса уже double, дополнительных указаний не требуется. Z>>потеря происходит при конвертации 0.9f в double. Z>>0.9 != (double)0.9f
PM>Почему так происходит? PM>Ведь PM>0.9 == 0.9f PM>0.9 == 0.9D PM>0.9 != (double)0.9f
PM>Из-за того что считывается странным образом константа при конвертации? Ведь 0.9 == 0.9f и 0.9 == 0.9D, почему 0.9 != (double)0.9f? PM>Как это увязать с кодировкой мантиссы итерационным делением на два? Ведь в дабл 0.9 == 0.9D все нормально кодируется и во флоат тоже? Почему потеря только при конвертации происходит?
Тут все понятно и логично.
При записи 0.9 (без суффикса) число считается в формате double. Разницу между 0.9f и 0.9d видно из моего предыдущего сообщения.
Почему нет округления (при выводе через WriteLine)? Возможно потому, что значащих цифр в double больше чем во float, и число 0.899999976158142 (полученное как приближенное представление во float числа 0.9) в формате double считается вполне себе "самостоятельным", а не приближенным значением 0.9, т.е. точности double-числа 0.899999976158142 не хватает чтобы считаться приближенным значением 0.9.
P.S. Все это лишь мои догадки и предположения. К сожалению, подтвердить ссылками на доки не могу.
О>Я думаю, что такое поведение (разница между первым и вторым вариантом) можно объяснить тем, что в фунции WriteLine (вариант 1) формат отображения числа с плавающей точкой, принимаемый по умолчанию, подразумевает округление этого числа (до скольких-то значащих цифр) именно при выводе на консоль. Когда же мы во втором варианте явно указываем формат, то здесь отображаются все знаки в соответствии с форматом — видно, что ни float ни double точно десятичное число не представлют, хотя значение в double более точно, чем во float. Значение же в Decimal — в точности равно 0.9.
Классный пример. Еще у кого есть 100% ответ? Выглядит как будто в double достаточно разрядов чтобы мантисса не казалась обрезанной из далека, а во float — не достаточно и мантисса даже с первого вгляда кажется плохой? Это 100% ответ?
Здравствуйте, PaulMinelly, Вы писали:
PM>Классный пример. Еще у кого есть 100% ответ? Выглядит как будто в double достаточно разрядов чтобы мантисса не казалась обрезанной из далека, а во float — не достаточно и мантисса даже с первого вгляда кажется плохой? Это 100% ответ?
Double.ToString Method
This version of the ToString method implicitly uses the general numeric format specifier ("G") and the NumberFormatInfo for the current culture.
The number is converted to the most compact of either fixed-point or scientific notation, depending on the type of the number and whether a precision specifier is present. If the precision specifier is omitted or zero, the type of the number determines the default precision, as indicated by the following list.
* Byte or SByte: 3
* Int16 or UInt16: 5
* Int32 or UInt32: 10
* Int64 or UInt64: 19
* Single: 7
* Double: 15
* Decimal: 29
Fixed-point notation is used if the exponent that would result from expressing the number in scientific notation is greater than -5 and less than the precision specifier; otherwise, scientific notation is used. The result contains a decimal point if required and trailing zeroes are omitted. If the precision specifier is present and the number of significant digits in the result exceeds the specified precision, then the excess trailing digits are removed by rounding.
Здравствуйте, Овощ, Вы писали:
О>Здравствуйте, PaulMinelly, Вы писали:
PM>>Классный пример. Еще у кого есть 100% ответ? Выглядит как будто в double достаточно разрядов чтобы мантисса не казалась обрезанной из далека, а во float — не достаточно и мантисса даже с первого вгляда кажется плохой? Это 100% ответ?
О>Double.ToString Method
О>This version of the ToString method implicitly uses the general numeric format specifier ("G") and the NumberFormatInfo for the current culture.
Открыл рефлектор,
вот как реализован в double
public override string ToString()
{
return Number.FormatDouble(this, null, NumberFormatInfo.CurrentInfo);
}
где в нем uses the general numeric format specifier ("G")? Карренирфо — вижу, G — нет.
Прочел всю ветку. ИМХО проблема в том что никто не сказал автору ветки что мантисса всегда дробная часть числла то есть всегда меньше 1. Таким образом 0.9 в виде 9х10**(-1) нельзя представить только 0.9х10**0. Поэтому возникает конвертация 0.9 в двоичную мантиссу и следовательно погрешность.
K>Прочел всю ветку. ИМХО проблема в том что никто не сказал автору ветки что мантисса всегда дробная часть числла то есть всегда меньше 1. Таким образом 0.9 в виде 9х10**(-1) нельзя представить только 0.9х10**0. Поэтому возникает конвертация 0.9 в двоичную мантиссу и следовательно погрешность.
Почему тогда она не возникает просто при прямом выводе флоат, децимал и не возникает при конвертации из флоат в строку?
Почему?
Console.Write("{0}\n", 0.9D); // returns 0.9
Console.Write("{0}\n", 0.9f); // returns 0.9
Console.Write("{0}\n", (float)0.9D); // returns 0.9
Console.Write("{0}\n", (double)0.9f); // А вот тут возникает! returns 0.899999976158142
Люди, поясните, еще 4 вопроса чтобы кашу в голове убрать полностью:
1. float и double регулируются одним стандартом: IEEE 754. Каким стандартом регулируется decimal?
2. Как понятно из IEEE 754 (http://en.wikipedia.org/wiki/IEEE_754),
float мантисса представляется 23-битным числом.
у double мантисса представляется 52-битным числом.
Сколько на самом деле бит в мантиссе в C# во флоате?
3. Если считать что во floate 23 бита на мантиссу и если перевести 0.9 вручную во float методом который описал Niswn d в посте выше, то получится РОВНО:
899999976158142
Почему Visual Studio урезает результат и выводит всего лишь 9 первых знаков вместо всех 16?:
Console.Write("{0:E40}\n", (float)0.9d);
899999976000000000
Почему не выводит ..."158142" ведь 23-битов для этого достаточно или же во флоате мантисса не 23 битная?
4. Сделал программку для перевода дробных чисел во float и обратно. Конвертировал 0.8 и у меня получилось:
11001100110011001100110 что равно = 0,7999999523162840000
Почему Визуал-Студия выводит:
(float) 0.8 == как 0.8000000120
вместо
0,7999999523162840000
Я ошибся в разрядности мантиссы во флоате?
Здравствуйте, PaulMinelly, Вы писали:
K>>Прочел всю ветку. ИМХО проблема в том что никто не сказал автору ветки что мантисса всегда дробная часть числла то есть всегда меньше 1. Таким образом 0.9 в виде 9х10**(-1) нельзя представить только 0.9х10**0. Поэтому возникает конвертация 0.9 в двоичную мантиссу и следовательно погрешность.
PM>Почему тогда она не возникает просто при прямом выводе флоат, децимал и не возникает при конвертации из флоат в строку? PM>Почему?
PM>Console.Write("{0}\n", 0.9D); // returns 0.9 PM>Console.Write("{0}\n", 0.9f); // returns 0.9 PM>Console.Write("{0}\n", (float)0.9D); // returns 0.9 PM>Console.Write("{0}\n", (double)0.9f); // А вот тут возникает! returns 0.899999976158142
PM>Чем последний случай такой особенный?
Последний случай особенный тем что там имеет место конвертация с удлиннением мантиссы от 4 байтового представления в 8 байтовое. Затем идет вывод значения и видимо конвертация происходит вот таким образом что результат 0.899999976158142. Это проблема конвертора Фреймворков а не ваша.