vak: (Знайка)
Serge Vakulenko ([personal profile] vak) wrote2023-01-14 02:45 pm

За что математики не любят компьютерную арифметику

#include <stdio.h>
int main ()
{
    if (-5.2 + 4.9 != -0.3) {
        printf("Oops!\n");
    }
    if (4.8 - 6.1 != -1.3) {
        printf("Oops!\n");
    }
    if (4.3 - 3.6 != 0.7) {
        printf("Oops!\n");
    }
}
Это мне надо было простенький тестик сварганить по работе, суммировать плавающие числа, а оно вон как боком выскочило.

nz

[personal profile] nz 2023-01-14 11:22 pm (UTC)(link)

Зачем так сложно, 0.1 + 0.2 != 0.3 же.

[personal profile] ichthuss 2023-01-14 11:30 pm (UTC)(link)
Кто использует с плавающими типами сравнения "==" и "!=", кроме очень специальных случаев, тот сам себе злобный буратино.

Тестик, в принципе, относится к этим специальным случаям. Тут можно воспользоваться простым подходом: использовать числа, кратные 1/2^n, где n < 24. Например, 0.25+0.375
Edited 2023-01-14 23:35 (UTC)
perdakot: (Default)

[personal profile] perdakot 2023-01-14 11:56 pm (UTC)(link)
Я хардвер проверя

Тогда, наверное, надо float раздербанить на знак, экспоненту и мантиссу (целые) и сравнивать их, а не плавучку.
dennisgorelik: 2020-06-13 in my home office (Default)

C#

[personal profile] dennisgorelik 2023-01-15 12:40 am (UTC)(link)
In C# floating point calculations are not precise too:
[TestMethod]
public void FloatingPointCheck()
{
	Assert.AreEqual(0.2, 0.1 + 0.1); // Passes
	Assert.AreEqual(3.0, 1.0 + 2.0); // Passes
	Assert.AreEqual(0.3, 0.1 + 0.2); // Fails
}
Edited 2023-01-15 00:40 (UTC)
ircicq: (Default)

[personal profile] ircicq 2023-01-15 12:47 am (UTC)(link)
Есть полезная статья G. Steele, Jon L. White - How to print floating-point numbers accurately

Там про десятичную печать, но алгоритм можно применить и для сравнения.
perdakot: (Default)

[personal profile] perdakot 2023-01-15 01:19 am (UTC)(link)
Это без разницы, сравнивать три поля по отдельности или всё слово целиком.

Не может быть, что копиляторы могут сделать мантиссу немного разную у плавучего литерала?
juan_gandhi: (Default)

[personal profile] juan_gandhi 2023-01-15 01:29 am (UTC)(link)

Вечная тема. вообще говоря, вопрос равенства вещественных чисел и теоретически сложен. Проще считать, что это не эквациональная теория.

juan_gandhi: (Default)

[personal profile] juan_gandhi 2023-01-15 01:39 am (UTC)(link)

Ну ты прям физик.

Мы не такие. Я когда-то эмулятор FPP писал, так обнаружил, что могу вполне, на тех 80 битах, выдать точность выше, чем настоящий FPP гонит. Там же еще один запасной бит был, не в регистрах, а в процессе вычислений.

archaicos: Шарж (Default)

[personal profile] archaicos 2023-01-15 02:07 am (UTC)(link)
Используй шестнадцатеричные вещественные константы типа 0x1p-1. Их уже давно завезли в С и C++.
archaicos: Шарж (Default)

[personal profile] archaicos 2023-01-15 03:21 am (UTC)(link)
Если он на плюсах, то стандартная библиотека конвертнёт, надо лишь распарсить.
Если на питоне, то надо поискать, может тоже простое решение. Хотя, шестнадцатеричное можно и самому преобразовать, т.к. сложное уже отсутствует.

если на плюсах ...

[personal profile] h1uke 2023-01-15 04:08 am (UTC)(link)
или на Питоне лезть на этот уровень --
то поневоле вспоминаешь древнюю формулу: "со свиным рылом в калашный ряд" :)

будто эти ваши плюсы, или там Питон - это не программы, написанные изначально на "лысом С"
sobriquet9: (Default)

[personal profile] sobriquet9 2023-01-15 05:53 am (UTC)(link)
Есть же DBL_EPSILON и std::numeric_limits::epsilon().

[personal profile] dijifi 2023-01-15 06:40 am (UTC)(link)
В начале моей карьеры видел я квадратный корень из четырех равный единице, но только для инструкции single precision. Глючный микрокод у железа. Так, вспомнилось.

[personal profile] dijifi 2023-01-15 08:02 am (UTC)(link)
В начале моей карьеры видел я квадратный корень из четырех равный единице, но только для инструкции single precision. Глючный микрокод у железа. Так, вспомнилось.
sobriquet9: (Default)

[personal profile] sobriquet9 2023-01-15 02:22 pm (UTC)(link)
Так оно и получается. Даже с дробями всё точно, только в двоичной системе. Хотите, чтоб в десятичной было точно - переделайте вычислитель, чтоб он считал в десятичной системе. Такое вроде уже ж было, какие-то компьютеры внутри себя считали всё в BCD.

А ещё лучше сразу в шестидесятиричной, как у древних египтян. Тогда на три тоже делить удобно будет.
dennisgorelik: 2020-06-13 in my home office (Default)

Re: C#

[personal profile] dennisgorelik 2023-01-15 04:01 pm (UTC)(link)
Is there a convenient way to use more precise representation?

ircicq: (Default)

Re: C#

[personal profile] ircicq 2023-01-15 07:15 pm (UTC)(link)
Type `decimal` in many programming languages including C#
Although it is slower

Edited 2023-01-15 19:15 (UTC)
dennisgorelik: 2020-06-13 in my home office (Default)

Re: C#

[personal profile] dennisgorelik 2023-01-15 08:40 pm (UTC)(link)
Oh.
[personal profile] vak meant "data representation in computer memory" (floating-point double vs decimal).
I thought he meant representation/conversion of data to decimal string.

In any case, the primary way to deal with imprecision is not increasing precision, but replacing number equality comparison with [epsilon] range comparison.
Edited 2023-01-15 20:41 (UTC)
dennisgorelik: 2020-06-13 in my home office (Default)

[personal profile] dennisgorelik 2023-01-16 05:50 am (UTC)(link)
> Hex literals work fine.

Hex interface is a good workaround.
But it may be hard to convince end users to use hex interface, right?
waqur: (Default)

[personal profile] waqur 2023-01-18 11:08 am (UTC)(link)
Не зря в банковской сфере так популярен COBOL, у которого развитая система целочисленных типов фиксированной ширины в десятичном представлении. Банкиры ещё в 70-е были не в восторге от всех этих фокусов с округлением вещественных чисел с плавающей точкой.