LINUX.ORG.RU

Цифры после нулей, в дробных числах. Откуда?! Полтора не полтора 0.о

 


0

1

Вот фиговина, и куда с ней идти я не догадываюсь. Для меня открытием стал тот факт что дробные числа, вида 1.52, 1.33, 0.1 и любые другие имеют после ряда нудей еще цифры отличные от 0. Вот пример.

1.33000000000000007105
0.76000000000000000888
1.52000000000000001776
3.04000000000000003553

А вывожу я их так

print(number_format(1.33, 20, '.',' '));
echo "<br>";
print(number_format(0.76, 20, '.',' '));
echo "<br>";
print(number_format(1.52, 20, '.',' '));
echo "<br>";
print(number_format(3.04, 20, '.',' '));
Что за херня? Откуда и почему после нулей еще какие-то значения?

К слову сказать в js получаем такой же результат, с него и началось.

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

Так интересно выглядит другой результат.

0.98999999999999999112
0.10000000000000000555
1.09000000000000007994

print(number_format(0.99, 20, '.',' '));
echo "<br>";
print(number_format(0.1, 20, '.',' '));
echo "<br>";
print(number_format(0.1+0.99, 20, '.',' '));

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

yvv ★★☆
()

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

peregrine ★★★★★
()
Последнее исправление: peregrine (всего исправлений: 1)
Ответ на: комментарий от yvv

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

peregrine ★★★★★
()
Ответ на: комментарий от peregrine

Кстати, именно из-за него сравнивать float-ы нельзя

Лучше писать «проверять равенство float-ов нельзя», а то научишь, а они потом вообще сравнивать перестанут.

Khnazile ★★★★★
()
Ответ на: комментарий от Khnazile

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

peregrine ★★★★★
()
Ответ на: комментарий от peregrine

реальная точность float-а не соответствует его диапазону, а составляет всего 7 знаков

То ли дело Real во Free Pascal'е на x86_64. Он автоматически соответствует Double (который можно и явно прописывать).

Ещё в Паскале есть такой тип дробных чисел как Currency

The Currency type is a real data type with 4 digits to the right of the decimal point and a range of -922337203685477.5808 to 922337203685477.5807 . The purpose of the Currency data type is to give arithmetic results that exactly correspond to decimal calculations on the input values.

Real values are normally stored in the binary number system internally, and calculations are performed in the CPU in binary arithmetic. Since humans desire input and output numbers to be in decimal number format, there must be a conversion made between external decimal numbers and their binary internal representation. As a result of the conversion to/from binary numbers and the calculations being done in binary arithmetic, the results of normal real arithmetic can differ from a decimal arithmetic calculation. This discrepancy is not critical in many applications, but financial applications want their arithmetic operations to match a decimal arithmetic calculation. The currency data type is designed to give arithmetic results corresponding to decimal arithmetic on the real values given.

saahriktu ★★★★★
()
Ответ на: комментарий от peregrine

Ну для меня «сравнение», это не только проверка равенства, но еще и проверка больше-меньше. И возможно я что-то не понимаю, но по-моему результат тут всегда однозначный, либо одно число больше (меньше) другого, либо нет. То, что не всегда очевидно, какое число в итоге получится больше это другой вопрос.

Khnazile ★★★★★
()

Откуда и почему

Floating-point arithmetic ©.

quickquest ★★★★★
()
Ответ на: комментарий от peregrine

Надо либо большую точность брать в виде double, либо вообще переходить на целочисленную арифметику.

Ви таг говогите, будто не существует number/decimal типов.

Shadow ★★★★★
()
Ответ на: комментарий от Shadow

А это разве не разновидности сахара над int-ом, либо за счёт фиксированного числа цифр после запятой, либо за счёт более глубокого обмазывания ООП-ом где все числа с которыми работает программист это классы.

anonymous
()
Ответ на: комментарий от peregrine

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

20.0 / 2.0 == 10.0

Deleted
()
Ответ на: комментарий от Khnazile

Если у тебя в коде стоит проверка "а=1.5; б=1.5; если а == б, то делай то-то … ", то не факт что она у тебя сработает, потому, что после 7 знака после запятой в а может быть 0, а в б - 1, к примеру и всё.

Поэтому сравнивают с некоторой точностью.

Почитай про сравнение float в си.

anonymous
()
Ответ на: комментарий от anonymous

Я про это знаю. Я говорю о другом сравнении а<б а>б, которое тоже сравнение, и вполне себе беспроблемно работает даже с float, а у тебя частный случай сравнения - проверка равенства. И даже проверка неравенства а!=б очень часто будет работать корректно, по этому нельзя заявлять о том, что «float сравнивать нельзя», это учит людей плохому.

Khnazile ★★★★★
()
Ответ на: комментарий от Deleted

Ага. Пусть у тебя было 2 разных float-а один получения как 2/3 а второй как 1-1/3. И тут в зависимости от железа и языка может начаться магия.

anonymous
()
Ответ на: комментарий от vodz

1/3 равно. Или ты не в курсе как пользоваться дробной записью чисел, которой раньше в школе учили? То что для компьютера считать так же как в тетрадке считают говноидея почти во всех задачах, это другой вопрос.

anonymous
()
Ответ на: комментарий от Khnazile

Чем это плохо не пользоваться тем, что не даёт гарантированного правильного результата? Ну и больше меньше тоже очень аккуратно надо сравнивать, держа в голове что у float 6-7 знаков можно сравнивать, а хранить можно от -3.4E-38 до -3.4E+38. А если у тебя важно точно сравнивать числа больше чем с 7 знаками после запятой, то нужен double но и он даёт гарантии только до 15-16 знаков. Если надо больше, то уже надо изголяться.

anonymous
()
Ответ на: комментарий от anonymous

1/3 равно.

Это другая запись равенства, негодное для хранения значения, в виде выражения с делением и оно таки равно действительному числу без точного значения, которое можно записать как 0.(3). Потому и 0.1 это тоже не точное число, но уже в двоичной системе и равно 0.0(9)8.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от anonymous

Чем это плохо не пользоваться тем, что не даёт гарантированного правильного результата?

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

Khnazile ★★★★★
()
Ответ на: комментарий от vodz

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

А в чем собственно проблема с тем, чтобы хранить рациональные дроби... в виде рациональных дробей? Отдельно числитель, отдельно знаменатель. Пока не возникнет необходимость использовать иррациональные числа, все будет хорошо, только очень меееееедленно.

Khnazile ★★★★★
()
Ответ на: комментарий от Khnazile

А в чем собственно проблема с тем, чтобы хранить рациональные дроби... в виде рациональных дробей? Отдельно числитель, отдельно знаменатель. Пока не возникнет необходимость использовать иррациональные числа, все будет хорошо, только очень меееееедленно.

Проблема в том, что мир намного сложнее задач, когда надо разделить N яблок на M ртов. Может там спин электрона проворачивается, и ток на самом деле таки 0.0(9)8 а не 10e**n/10e**(n+1) Ампер. И потому нет никакого смысла в хранении дробей.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

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

Другое дело, нужно ли это для конкретной задачи.

Deleted
()
Ответ на: комментарий от Deleted

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

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

vodz ★★★★★
()
Ответ на: комментарий от anonymous

Ага. Пусть у тебя было 2 разных float-а один получения как 2/3 а второй как 1-1/3. И тут в зависимости от железа и языка может начаться магия.

На практике обычно нужны не 2/3 с бесконечной точностью, например, 0.67. round(x1 * 100.0) == round(x2 * 100.0)

Если нужна высокая точность, от float-ов придётся отказаться.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от aquadon

Ну всем нужен Pascal.

Ну всем

За такую опечатку можно схлопотать тапком по наглой чёрной кошачьей морде :)

Deleted
()
Ответ на: комментарий от no-such-file

Стоит отметить, что вот у меня самая что ни на есть профильная вышка, но этот вопрос в явном виде как-то не рассматривался. Сам прочитал где-то. Может кому-то лабораторка на тему float-ов и сопроцессора попалась в курсе «Архитектуры ЭВМ» и там его настигало просветление, но у меня лично было другое задание, на всякие MMX инструкции

Harald ★★★★★
()
Ответ на: комментарий от Harald

самая что ни на есть профильная вышка, но этот вопрос в явном виде как-то не рассматривался

В профильной вышке и не рассматривается? Ну чёт не верится, неужели числа в двоичную систему и обратно не переводили на семинарах? Да даже тупо на лекциях по матану в теме о вещественных числах редко какой препод удержится от практических примеров с представлением чисел на компах.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от vodz

негодное для хранения значения

Это кто вам такую глупость сказал? 1/3*1/5+14/15=1 О как негодные числа точно посчитались в годное.

peregrine ★★★★★
()
Ответ на: комментарий от peregrine

Это кто вам такую глупость сказал?

Я вполне могу не слушать чужие глупости, в отличии от некоторых.

1/3

С чего вы взяли, что 1/3 - это верное значение, а 0. и 15 троек и ноль - неверное? Ах, одно яблоко на три рта поделили? А кто вам сказал, что это тут вот такой детсад расчитывается?

vodz ★★★★★
()
Ответ на: комментарий от vodz

С чего вы взяли, что 1/3 - это верное значение, а 0. и 15 троек и ноль - неверное

С того, что я умею считать числа больше 15 знаков и знаю про числа с дробной частью в периоде, к которым относится 1/3. Как и прекрасно знаю, что такое приближенные вычисления и точные.

peregrine ★★★★★
()
Ответ на: комментарий от peregrine

Как и прекрасно знаю, что такое приближенные вычисления и точные.

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

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от Harald

пределы, производные, интегралы, диффуры :)

ЛОЛ, а как можно определить предел, не определив сначала понятие точной верхней/нижней грани, непрерывности на множестве вещественных чисел, собственно множества вещественных чисел? Открой любой учебник матана не 100-летней давности (тот же Зорич, Кудрявцев) и там это первые главы.

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

no-such-file ★★★★★
()
Ответ на: комментарий от vodz

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

А что религия запрещает использовать «другую» запись? Оно вполне годное для хранения и с ним можно производить точные операции. Это даже в начальной школе делают. Я тебе больше скажу, с помощью символьных вычислений можно даже pi и sqrt(2) точно хранить и выполнять точные операции. Внезапно да?

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

А что религия запрещает использовать «другую» запись? Оно вполне годное для хранения и с ним можно производить точные операции. Это даже в начальной школе делают. Я тебе больше скажу, с помощью символьных вычислений можно даже pi и sqrt(2) точно хранить и выполнять точные операции. Внезапно да?

Вот именно, что только в начальной школе и делают. А потом вдруг оказывается, что когда поделили яблоко на 3 части, а потом измерили, то получили, что 2 части и у нас 0, и 10 троек и ноль, а третья - 0.десять троек и 9. Где одиннадцатая единичка погрешность и утруска. Но это правильное значение, а не 1/3, нет в мире дробей, я не могу вспомнить что в реальном мире делят на три и юзают точное мат. значение периодической дроби, если оно изначально не кратно 3.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)

С одной стороны, хорошо, что «открыл для себя» это дело.

С другой стороны, страшно становится смотреть на уровень нынешних айтишников…

Alve ★★★★★
()
Ответ на: комментарий от no-such-file

Так бы сразу и сказал.

Не, я сразу говорю, что в двоичной системе 0.1 это 0.0(9)8 и никого это не парит. А если вам надо математику, так лучше символьную юзайте, а не лезте со своими дурацкими дробями, никакого отношения не имеющие к конкретным задачам, кроме тормозов и чсв.

vodz ★★★★★
()

полтора бывает и литр 45, и литр 35, и даже литр 30

buratino ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.