Здравствуйте, LaptevVV, Вы писали:
KP>>Можно ли без округления вычислить c, чтобы гарантировать (b+c) == a? Спасибо. LVV>Даже (со)процессор делает округление.
Да тут даже до процессора дело не всегда доходит.
Компилятор выкидывает ненужные вычисления и заменяет тело функции на прямой вызов assert_fail. Не нужны в машинном коде эти ваши сравнения, если и так всё понятно
Здравствуйте, Kazmerchuk Pavel, Вы писали:
KP>Можно ли без округления вычислить c, чтобы гарантировать (b+c) == a?
Разница двух double чисел не всегда представима в double без потери точности.
То есть для double ответ — нельзя.
Если необходимо считать точно подобные суммы, то тут поможет только длинная арифметика (с хранением всех значащих бит). Но понятно, что не всегда подходит и всё это довольно далеко от стандартного типа double.
А так, операции в IEEE754 c floating-point не ассоциативные. То есть в них принципиально не выполняется равенство (a + b) + c == a + (b + c).
Нужно с этим уметь жить и писать алгоритмы соответствующим образом.
Например, этот эффект можно учитывать и минимизировать как в алгоритме суммирования Кэхэна. Заметь, что там тоже повторяется похожий паттерн из действий c = a — b; t = b + c; почти как у тебя в примере.
Либо этот эффект можно даже эксплуатировать во благо, например, для быстрого округления чисел без преобразования типов:
Ну и ещё можно упомянуть, что компилятору обычно можно сказать, что он должен считать, что floating-point ассоциативный (например, через ключ -ffast-math в gcc/clang). Тогда он будет генерировать машинный код исходя из предположений, что (a+b)-b можно заменить сначала на a+(b-b), и потом на просто a (да, случай с NaN тоже считается несуществующим). Но не советую идти этой дорогой: тут наоборот сломаются хорошие алгоритмы, которые написаны в рассчёте на гарантии и поведение ieee754. То есть они будут выдавать иногда чушь, но зато работать будет быстро
Здравствуйте, Kazmerchuk Pavel, Вы писали:
KP>Можно ли без округления вычислить c, чтобы гарантировать (b+c) == a? Спасибо.
Можно, но для начала тебе нужно открыть любой учебник по вычислениям на компьютерах и внимательно прочитать и всё поймешь, что можно, что нельзя. Раньше в школе основы оного преподавали. "Значашие цифры", "системы счисления", "периодические и не периодические дроби", "целые, рациональные и иррациональные числа" — это, например, из тех основ.
Здравствуйте, Vzhyk2, Вы писали:
KP>>Можно ли без округления вычислить c, чтобы гарантировать (b+c) == a? Спасибо. V>Можно, но для начала тебе нужно открыть любой учебник по вычислениям на компьютерах и внимательно прочитать и всё поймешь, что можно, что нельзя. Раньше в школе основы оного преподавали. "Значашие цифры", "системы счисления", "периодические и не периодические дроби", "целые, рациональные и иррациональные числа" — это, например, из тех основ.
Не совсем понятно, как ты увязал школьную программу и вычисления на компьютерах. Перечисленное — это основы алгебры, скорее. А системы счисления — если и давали, то в конечных классах
Здравствуйте, Marty, Вы писали:
M>Ну, смотря где и как. Домашнюю бухгалтерию вести очень удобно
Домашнюю бухгалтерию можно просто вести в копейках.
M>Медленнее, да — сравнение в 5, сложение и вычитание — в 20, умножение — в 50, про деление вообще не говорю — раз медленнее, чем встроенный double. Но по сравнению с тем же cpp_dec_float из буста — уже не на порядки, а в разы отстаю. И там опять же используется двоичная арифметика.
Логично, в компе в принципе используются двоичные вычисления.
M>Но таки очень удобно оказалось. Где скорость не критична, а важна точность — уже перехожу на свой велосипед
Слово "точность" здесь неуместно.
M>Понятно, что не сработает.
Тогда ради чего огород?
Если ради больших чисел не поддерживаемых напрямую процессором, то и их проще и быстрее во всех отношениях сделать двоичными. Или из предположения, что "неудобное" деление не будет использоваться? Тогда проще вести расчеты в двоичных с фиксированной точкой.
M>Но у меня эпсилон для сравнения можно с любым количеством знаков задать в виде строки. И не важно, какого порядка будут величины.
Ну вот, и здесь пришлось эпсилон использовать
M>У меня потеря значащих цифр только при делении происходит, все остальные операции, хоть сколько раз складывай/вычитай/умножай — ни одного знака потеряно не будет.
И это портит всю затею, демонстрируя её бессмысленность.
M>А по поводу правильного сравнения машинных floating point чисел — ну, на диссер конечно тема недотягивает, но там одним эпсилон не отделаешься
Это в самом общем случае, в частных имея представление о задаче, о её "физическом" смысле и о возможных окончательных и промежуточных итогах все проще.
Здравствуйте, Kazmerchuk Pavel, Вы писали:
KP>Есть функция (сеточная), заданная значениями в некоторых точках (узлах). Количество и расположение узлов произвольное. Есть система дифференциальных уравнений (ДУ), которая интегрируется численным методом. Правые части системы ДУ зависят от сеточной функции. Численный метод получает на вход в том числе шаг (по времени). Длинна шага каждый раз вычисляется исходя и требуемой точности интегрирования. Проблема в том, что сеточная функция имеет разрывы в узлах. Если метод интегрирования не попадает в точки разрыва, он теряет точность. Я вычисляю шаг до следующего узла (как написали выше) и ошибку. Если ошибка нулевая — попадем точно в узел, всё ОК, если нет, корректирую шаг чтобы гарантировано не "перепрыгнуть" узел.
Чего-то не доходит. Если шаг должен попадать в узлы, то его не надо корректировать, его надо сразу дискретным делать так, чтобы соответствовал узлам.
KP>Можно ли без округления вычислить c, чтобы гарантировать (b+c) == a? Спасибо.
Нет. Даже (со)процессор делает округление.
Тип округления устанавливается в одном из регистров сопроцессора.
без округления выполняются операции со степенями двойки: 1/2 = 2^(-1), 1/4 = 2^(-2) и т.д.
Но и в этом случае выполняется нормализация, при которой младшие разряды результата могут исчезнуть.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, LaptevVV, Вы писали:
LVV>Нет. Даже (со)процессор делает округление.
А вычислить дополнительную поправку к с, чтобы, например (b + c + correction) == a?
KP> double a = 0.014390783999999978;
KP> double b = 0.052996730719235739;
KP> double c = a - b; //-0.038605946719235763
KP>
KP>Можно ли без округления вычислить c, чтобы гарантировать (b+c) == a? Спасибо.
Нет. double умеет не больше 15ти значащих десятичных знаков хранить, а у тебя — 17. А тут a и b сразу уже хранят не те значения, которые ты им задаёшь. По идее, компилятор должен предупредить об этом, но не факт
это или UB или не UB
а какое там представление он имеет в каком компилере до одного места
что то годболд msvс перестал у меня показывать
остальные gcc clang ok
Здравствуйте, Homunculus, Вы писали:
H>Забудь про «==« для плавающей точки. Только разницу с эпсилон сравнивай
Чушь. Всё зависит от того, что именно ты хочешь сделать и где.
Здравствуйте, Marty, Вы писали:
M>Нет. double умеет не больше 15ти значащих десятичных знаков хранить, а у тебя — 17. А тут a и b сразу уже хранят не те значения, которые ты им задаёшь. По идее, компилятор должен предупредить об этом, но не факт
А еще в советской школе рассказывали про погрешности округления и что с ними происходит при вычислениях.
Здравствуйте, watchmaker, Вы писали:
W>Ну и ещё можно упомянуть, что компилятору обычно можно сказать, что он должен считать, что floating-point ассоциативный (например, через ключ -ffast-math в gcc/clang). Тогда он будет генерировать машинный код исходя из предположений, что (a+b)-b можно заменить сначала на a+(b-b), и потом на просто a (да, случай с NaN тоже считается несуществующим). Но не советую идти этой дорогой: тут наоборот сломаются хорошие алгоритмы, которые написаны в рассчёте на гарантии и поведение ieee754. То есть они будут выдавать иногда чушь, но зато работать будет быстро
Это нехорошие алгоритмы, хорошие обычно делают устойчивыми и им пофиг на твои ключики компилятору.
LVV>>Нет. Даже (со)процессор делает округление. KP>А вычислить дополнительную поправку к с, чтобы, например (b + c + correction) == a?
Надо хорошо разбираться в теории погрешностей — есть такая теория...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Vzhyk2, Вы писали:
M>>Нет. double умеет не больше 15ти значащих десятичных знаков хранить, а у тебя — 17. А тут a и b сразу уже хранят не те значения, которые ты им задаёшь. По идее, компилятор должен предупредить об этом, но не факт V>А еще в советской школе рассказывали про погрешности округления и что с ними происходит при вычислениях.
Здравствуйте, Vzhyk2, Вы писали:
V>Здравствуйте, Kazmerchuk Pavel, Вы писали:
KP>>Можно ли без округления вычислить c, чтобы гарантировать (b+c) == a? Спасибо. V>Можно...
Покажи или топик не засоряй
Здравствуйте, flаt, Вы писали:
R>>>long double
M>>Который в MSVC, внезапно, тот же double
F>И который в ICC (который, в свою очередь, совместим с MSVC) таки long double (80 bit).
Как совместим? По ключам командной строки?
В итоге-то что? В MSVC long double как-то не превращается в double, или что?
Я еще с борманом наелся этого в прошлом веке, теперь только double и float.
Здравствуйте, Marty, Вы писали:
M>Как совместим? По ключам командной строки?
По сорцам (всякие прагмы и прочее) и по ключам командной строки (он как clang, имеет режимы совместимости с GCC и MSVC).
M>В итоге-то что? В MSVC long double как-то не превращается в double, или что?
В ICC — нет, не превращается (но, кажется, там есть ключик и long double может быть как 64, так и 80 бит).
Здравствуйте, flаt, Вы писали:
M>>Как совместим? По ключам командной строки?
F>По сорцам (всякие прагмы и прочее) и по ключам командной строки (он как clang, имеет режимы совместимости с GCC и MSVC).
Отлично. Мы разобрались, что ICC совместим с MSVC в командной строке и по сорцам.
Как это отменяет то, что MSVC не умеет в double больше 64х бит?
M>Отлично. Мы разобрались, что ICC совместим с MSVC в командной строке и по сорцам.
M>Как это отменяет то, что MSVC не умеет в double больше 64х бит?
А речь не об отмене. Человек предложил long double, в ответ было сказано, что под MSVC long double не работает (хотя топикстартер платформу не указывал). Но если под MSVC не работает, то есть ещё ICC, который совместим с MSVC.
Здравствуйте, flаt, Вы писали:
M>>Отлично. Мы разобрались, что ICC совместим с MSVC в командной строке и по сорцам.
M>>Как это отменяет то, что MSVC не умеет в double больше 64х бит?
F>А речь не об отмене. Человек предложил long double, в ответ было сказано, что под MSVC long double не работает (хотя топикстартер платформу не указывал). Но если под MSVC не работает, то есть ещё ICC, который совместим с MSVC.
Ну и после ICC с другим компилятором у него все поломается. Годный рецепт.
M>Ну и после ICC с другим компилятором у него все поломается. Годный рецепт.
Это конечно занятно, про long double, MSVC, ICC и всех, всех, всех... только что это в принципе меняет? Да ничего, ну получится больше значащих цифр, но на них все равно проявятся особенности представления чисел с плавающей точкой.
Ответ другой и очень простой, его Homunculus уже написал.
Здравствуйте, pagid, Вы писали:
P>Здравствуйте, Kazmerchuk Pavel, Вы писали:
KP>>А вычислить дополнительную поправку к с, чтобы, например (b + c + correction) == a? P>А цель какая?
Решение уже привели. Задача шагать по сеточной функции, точно попадая в узлы. Узлы подвижны.
Ну, смотря где и как. Домашнюю бухгалтерию вести очень удобно
Медленнее, да — сравнение в 5, сложение и вычитание — в 20, умножение — в 50, про деление вообще не говорю — раз медленнее, чем встроенный double. Но по сравнению с тем же cpp_dec_float из буста — уже не на порядки, а в разы отстаю. И там опять же используется двоичная арифметика.
Но таки очень удобно оказалось. Где скорость не критична, а важна точность — уже перехожу на свой велосипед
P>И как у тебя сработает? P>int main() P>{ P> MartyNumber a = 1.0; P> MartyNumber b = a/3;
P> assert((b+b+b) == a); P>}
Понятно, что не сработает. У меня для оператора деления используется static поле, содержащее точность. По умолчанию — 18 знаков после точки (при этом не важно, сколько до). Отдельно есть метод div, там точность можно явно задать.
Ясно, что 1/3 в десятичном виде точно не представима.
Но у меня эпсилон для сравнения можно с любым количеством знаков задать в виде строки. И не важно, какого порядка будут величины.
У меня потеря значащих цифр только при делении происходит, все остальные операции, хоть сколько раз складывай/вычитай/умножай — ни одного знака потеряно не будет.
А по поводу правильного сравнения машинных floating point чисел — ну, на диссер конечно тема недотягивает, но там одним эпсилон не отделаешься
Здравствуйте, pagid, Вы писали:
P>Ответ другой и очень простой, его Homunculus уже написал.
Слишком простой, тема сравнения плавающих чисел поширше будет. В универе по этим делам вообще два семестра выч мата было, как раз на тему, как считать на double и прочем плавающем
Здравствуйте, Kazmerchuk Pavel, Вы писали:
KP>Решение уже привели. Задача шагать по сеточной функции, точно попадая в узлы. Узлы подвижны.
Решение с эпсилон проще и эффективнее. Еще можно целочисленную сетку взять. Тоже проще будет.
Здравствуйте, Marty, Вы писали:
M>Слишком простой, тема сравнения плавающих чисел поширше будет. В универе по этим делам вообще два семестра выч мата было, как раз на тему, как считать на double и прочем плавающем
В вопросе ТС нет на два семестра.
Здравствуйте, B0FEE664, Вы писали:
BFE>А теперь тоже самое для крайне правой десятичной цифры. например, 0.1 + 0.2 = ?
Я говорил про можно, то бишь существует, а не всегда, то бишь для любых.
А чтобы понимать, почему не для любых достаточно школьной программы.
Здравствуйте, Marty, Вы писали:
M>Слишком простой, тема сравнения плавающих чисел поширше будет. В универе по этим делам вообще два семестра выч мата было, как раз на тему, как считать на double и прочем плавающем
Что вы 2 семестра делали в университете на выч мате???
Здравствуйте, Vzhyk2, Вы писали:
M>>Слишком простой, тема сравнения плавающих чисел поширше будет. В универе по этим делам вообще два семестра выч мата было, как раз на тему, как считать на double и прочем плавающем V>Что вы 2 семестра делали в университете на выч мате???
Здравствуйте, Vzhyk2, Вы писали:
M>>Считали всякий матан численными методами на компе V>Тогда понятно.
V>У нас считать на EC1035 было мало. Мы разбирали теорию построения численных методов, что почему и как. Изучали типичные подходы с кучей теорем.
Такое тоже было, только я ничего не помню
Без теории, так-то, особого смысла считать нет — хрень насчитаешь, обязательно что-нибудь либо сойдётся не там, где должно, либо разойдётся там, где не должно, и пр
Здравствуйте, Marty, Вы писали:
M> У меня потеря значащих цифр только при делении происходит, все остальные операции, хоть сколько раз складывай/вычитай/умножай — ни одного знака потеряно не будет.
Тут тоже не всё так просто. Поумножай, скажем 1.00001*1.00001*...*1.00001 миллион раз.. сколько знаков будет? Так что тут нет универсального решения. Где сколько знаков должно диктоваться бизнес-требованиями, я не "правильными" библиотеками.
Здравствуйте, ·, Вы писали:
M>> У меня потеря значащих цифр только при делении происходит, все остальные операции, хоть сколько раз складывай/вычитай/умножай — ни одного знака потеряно не будет. ·>Тут тоже не всё так просто. Поумножай, скажем 1.00001*1.00001*...*1.00001 миллион раз.. сколько знаков будет? Так что тут нет универсального решения. Где сколько знаков должно диктоваться бизнес-требованиями, я не "правильными" библиотеками.
Ну, я не ограничиваю число знаков при умножении. Так что у меня получится очень много знаков после запятой, на x86 даже адресного пространства не хватит. Тут пользователь — ССЗБ. Если надо много умножать, пусть пользователь округляет сам, метод для этого есть, реализованы практически все виды округления, которые нашел в вики.
Для домашней бухгалтерии же важно, чтобы ни один десятичный знак не пропадал, а деление там — довольно редкая операция, и результаты его обычно используются в качестве вывода, без особого участия в прочих расчётах. Типа купили тут по столько, там по столько, в среднем получилось столько-то за штуку. А ели результат деления и используется в расчётах, то обычно что и как округлять зарегулированно/зарегламентированно.
Но вообще, я и в численных всяких вычислениях попробовал эти десятичные числа использовать, где особо не тороплюсь. И мне понравилось. Одна возможность тупого сравнения без всяких плясок с эпсилон и прочими дорого стоит. Тупо округляем оба числа, например, до 9 знаков после точки, и так же тупо сравниваем. И всё.
Или возможность точного деления с остатком для чисел с плавающей точкой. 1.41 делим на 0.2, на выходе — 7, остаток — 0.01. И всё предельно точно, без каких-либо неявных округлений/усечений и пр. Песня же
Здравствуйте, Marty, Вы писали:
M>>> У меня потеря значащих цифр только при делении происходит, все остальные операции, хоть сколько раз складывай/вычитай/умножай — ни одного знака потеряно не будет. M>·>Тут тоже не всё так просто. Поумножай, скажем 1.00001*1.00001*...*1.00001 миллион раз.. сколько знаков будет? Так что тут нет универсального решения. Где сколько знаков должно диктоваться бизнес-требованиями, я не "правильными" библиотеками. M>Ну, я не ограничиваю число знаков при умножении. Так что у меня получится очень много знаков после запятой, на x86 даже адресного пространства не хватит. Тут пользователь — ССЗБ. Если надо много умножать, пусть пользователь округляет сам, метод для этого есть, реализованы практически все виды округления, которые нашел в вики.
Ну т.е. опять не универсальный всемогутер, а надо понимать что округлять таки надо.
M>Для домашней бухгалтерии же важно, чтобы ни один десятичный знак не пропадал, а деление там — довольно редкая операция, и результаты его обычно используются в качестве вывода, без особого участия в прочих расчётах. Типа купили тут по столько, там по столько, в среднем получилось столько-то за штуку. А ели результат деления и используется в расчётах, то обычно что и как округлять зарегулированно/зарегламентированно.
В бухгалтерии просто считают в копейках и проблем никаких.
M>Но вообще, я и в численных всяких вычислениях попробовал эти десятичные числа использовать, где особо не тороплюсь. И мне понравилось. Одна возможность тупого сравнения без всяких плясок с эпсилон и прочими дорого стоит. Тупо округляем оба числа, например, до 9 знаков после точки, и так же тупо сравниваем. И всё.
Да ты сравниваешь плавающую и фиксированную точку, разные вещи с разным предназначением. Если ты применял плавучку в ситуации, когда требуется фиксированная точка — ССЗБ.
M>Или возможность точного деления с остатком для чисел с плавающей точкой. 1.41 делим на 0.2, на выходе — 7, остаток — 0.01. И всё предельно точно, без каких-либо неявных округлений/усечений и пр. Песня же
А почему не 7.005 и остаток 0.005? Т.е. у тебя какие-то конкретные требования в твоей конкретной задаче... и ясен пень алгоритм заточенный под конкретные требования лучше. Не вижу о чём тут петь...
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
M>>Ну, я не ограничиваю число знаков при умножении. Так что у меня получится очень много знаков после запятой, на x86 даже адресного пространства не хватит. Тут пользователь — ССЗБ. Если надо много умножать, пусть пользователь округляет сам, метод для этого есть, реализованы практически все виды округления, которые нашел в вики. ·>Ну т.е. опять не универсальный всемогутер, а надо понимать что округлять таки надо.
Понимать надо, да. Чисто теоретически, конечно можно сделать лимит для умножения, допустим, в несколько тыщь знаков после точки. В принципе, это идея — добавить как опцию.
Но вообще, если человек на C++ пишет — то он всё-таки что-то, хоть краем уха, да слышал и немного понимает
M>>Для домашней бухгалтерии же важно, чтобы ни один десятичный знак не пропадал, а деление там — довольно редкая операция, и результаты его обычно используются в качестве вывода, без особого участия в прочих расчётах. Типа купили тут по столько, там по столько, в среднем получилось столько-то за штуку. А ели результат деления и используется в расчётах, то обычно что и как округлять зарегулированно/зарегламентированно. ·>В бухгалтерии просто считают в копейках и проблем никаких.
Ну, у меня домашняя бухгалтерия — она такая, "домашняя". Как минимум, сотые доли копеек очень в ходу. И проблем там на самом деле выше крыши. Например, "банковское" округление придумали не для того, чтобы на ровном месте новых проблем изобрести.
M>>Но вообще, я и в численных всяких вычислениях попробовал эти десятичные числа использовать, где особо не тороплюсь. И мне понравилось. Одна возможность тупого сравнения без всяких плясок с эпсилон и прочими дорого стоит. Тупо округляем оба числа, например, до 9 знаков после точки, и так же тупо сравниваем. И всё. ·>Да ты сравниваешь плавающую и фиксированную точку, разные вещи с разным предназначением. Если ты применял плавучку в ситуации, когда требуется фиксированная точка — ССЗБ.
Ну, у меня я бы не сказал, что точка фиксированная. Вполне себе плавает. Фикс точка — это когда, например, берем int64_t, и говорим, что младшие 32 бита — дробная часть, старшие — целая часть. У меня вполне себе точка плавающая, просто я не упаковался в фиксированный размер представления. Тут интересно вообще, как такое представление назвать? Не фикс — явно, но и не привычная плавучка — тоже. Надо наверно как-то отдельно называть такой способ представления чисел.
M>>Или возможность точного деления с остатком для чисел с плавающей точкой. 1.41 делим на 0.2, на выходе — 7, остаток — 0.01. И всё предельно точно, без каких-либо неявных округлений/усечений и пр. Песня же ·>А почему не 7.005 и остаток 0.005?
Ну, деление с остатком обычно говорит нам, сколько целых раз делитель содержится в делимом. Да, операция обычно определена для целых, когда и делимое и делитель — целые.
·>Т.е. у тебя какие-то конкретные требования в твоей конкретной задаче... и ясен пень алгоритм заточенный под конкретные требования лучше. Не вижу о чём тут петь...
Домашняя бухгалтерия, она такая
Да и вообще, я просто немного попиарил свой классик, и всё
Здравствуйте, Marty, Вы писали:
M>>>Ну, я не ограничиваю число знаков при умножении. Так что у меня получится очень много знаков после запятой, на x86 даже адресного пространства не хватит. Тут пользователь — ССЗБ. Если надо много умножать, пусть пользователь округляет сам, метод для этого есть, реализованы практически все виды округления, которые нашел в вики. M>·>Ну т.е. опять не универсальный всемогутер, а надо понимать что округлять таки надо. M>Понимать надо, да. Чисто теоретически, конечно можно сделать лимит для умножения, допустим, в несколько тыщь знаков после точки. В принципе, это идея — добавить как опцию. M>Но вообще, если человек на C++ пишет — то он всё-таки что-то, хоть краем уха, да слышал и немного понимает
There are exactly 3.00000000000000042 hard things in programming — cache invalidation, naming things, off-by-1 errors and floating point.
M>>>Для домашней бухгалтерии же важно, чтобы ни один десятичный знак не пропадал, а деление там — довольно редкая операция, и результаты его обычно используются в качестве вывода, без особого участия в прочих расчётах. Типа купили тут по столько, там по столько, в среднем получилось столько-то за штуку. А ели результат деления и используется в расчётах, то обычно что и как округлять зарегулированно/зарегламентированно. M>·>В бухгалтерии просто считают в копейках и проблем никаких. M>Ну, у меня домашняя бухгалтерия — она такая, "домашняя". Как минимум, сотые доли копеек очень в ходу. И проблем там на самом деле выше крыши. Например, "банковское" округление придумали не для того, чтобы на ровном месте новых проблем изобрести.
Ну в сотых копейках, не важно. Важно что арифметика целочисленная в бухгалтерии.
M>>>Но вообще, я и в численных всяких вычислениях попробовал эти десятичные числа использовать, где особо не тороплюсь. И мне понравилось. Одна возможность тупого сравнения без всяких плясок с эпсилон и прочими дорого стоит. Тупо округляем оба числа, например, до 9 знаков после точки, и так же тупо сравниваем. И всё. M>·>Да ты сравниваешь плавающую и фиксированную точку, разные вещи с разным предназначением. Если ты применял плавучку в ситуации, когда требуется фиксированная точка — ССЗБ. M>Ну, у меня я бы не сказал, что точка фиксированная. Вполне себе плавает. Фикс точка — это когда, например, берем int64_t, и говорим, что младшие 32 бита — дробная часть, старшие — целая часть. У меня вполне себе точка плавающая, просто я не упаковался в фиксированный размер представления. Тут интересно вообще, как такое представление назвать? Не фикс — явно, но и не привычная плавучка — тоже. Надо наверно как-то отдельно называть такой способ представления чисел.
Нет, фиксированная точка это когда ты явно хранишь фиксированное число знаков после запятой. Притом знаки могут быть как двоичные (double), так и десятичные (java.lang.BigDecimal или аналог какой-нибудь). А в int64 или byte[] — это уже детали реализации. int64 просто ограничивает тем, что ты не можешь хранить больше, чем 18 десятичных знаков.
M>>>Или возможность точного деления с остатком для чисел с плавающей точкой. 1.41 делим на 0.2, на выходе — 7, остаток — 0.01. И всё предельно точно, без каких-либо неявных округлений/усечений и пр. Песня же M>·>А почему не 7.005 и остаток 0.005? M>Ну, деление с остатком обычно говорит нам, сколько целых раз делитель содержится в делимом. Да, операция обычно определена для целых, когда и делимое и делитель — целые.
Ну и остаток определён для целых как правило... А можно и написать что результат 8 и остаток -0.99
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
M>>Но вообще, если человек на C++ пишет — то он всё-таки что-то, хоть краем уха, да слышал и немного понимает ·>There are exactly 3.00000000000000042 hard things in programming — cache invalidation, naming things, off-by-1 errors and floating point.
А у меня можно и 3.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042 и ничего не потеряется.
Масштаб одной из проблем, согласись, несколько уменьшился, не?
Кстати, а что за проблема "off-by-1 errors"?
M>>·>В бухгалтерии просто считают в копейках и проблем никаких. M>>Ну, у меня домашняя бухгалтерия — она такая, "домашняя". Как минимум, сотые доли копеек очень в ходу. И проблем там на самом деле выше крыши. Например, "банковское" округление придумали не для того, чтобы на ровном месте новых проблем изобрести. ·>Ну в сотых копейках, не важно. Важно что арифметика целочисленная в бухгалтерии.
Ну они таки делят. Уже известен способ целочисленного деления без потерь знаков?
M>>Ну, у меня я бы не сказал, что точка фиксированная. Вполне себе плавает. Фикс точка — это когда, например, берем int64_t, и говорим, что младшие 32 бита — дробная часть, старшие — целая часть. У меня вполне себе точка плавающая, просто я не упаковался в фиксированный размер представления. Тут интересно вообще, как такое представление назвать? Не фикс — явно, но и не привычная плавучка — тоже. Надо наверно как-то отдельно называть такой способ представления чисел. ·>Нет, фиксированная точка это когда ты явно хранишь фиксированное число знаков после запятой.
Ну, хз. Про фиксированную точку 99% публикаций — о тех случаях, когда точка прибита гвоздями. А оставшийся 1% я не видел
·>Притом знаки могут быть как двоичные (double),
double — это вроде не про фиксированную точку
·>так и десятичные (java.lang.BigDecimal или аналог какой-нибудь). А в int64 или byte[] — это уже детали реализации. int64 просто ограничивает тем, что ты не можешь хранить больше, чем 18 десятичных знаков.
Ну вот я просто и запилил аналог java.lang.BigDecimal. Ни в плюсах, ни в кути — почему-то нет. Хотя вроде Qt умеет в базы данных, а во многих СУБД — NUMBER(M,N) — вполне родной формат. Почему до сих пор не сделали — я хз. Вот я это и исправил, как минимум, для себя.
M>>>>Или возможность точного деления с остатком для чисел с плавающей точкой. 1.41 делим на 0.2, на выходе — 7, остаток — 0.01. И всё предельно точно, без каких-либо неявных округлений/усечений и пр. Песня же M>>·>А почему не 7.005 и остаток 0.005? M>>Ну, деление с остатком обычно говорит нам, сколько целых раз делитель содержится в делимом. Да, операция обычно определена для целых, когда и делимое и делитель — целые. ·>Ну и остаток определён для целых как правило... А можно и написать что результат 8 и остаток -0.99
Можно и так считать, да. Поэтому у меня и нету метода mod, а только mod_helper (без учёта знака) — а кому надо, пусть сами допиливают на его базе. Но вообще думаю впилить, так, чтобы вёл себя аналогично целочисленному делению (возвращал всегда целое) и оператору '%' в C++.
С остатком от деления общественность вообще до сих пор не определилась, везде по-разному
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, ·, Вы писали:
M>>>Но вообще, если человек на C++ пишет — то он всё-таки что-то, хоть краем уха, да слышал и немного понимает M>·>There are exactly 3.00000000000000042 hard things in programming — cache invalidation, naming things, off-by-1 errors and floating point. M>А у меня можно и 3.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042 и ничего не потеряется.
Нигде ничего "не теряется", а отбрасывается. Оно у тебя теряется если ты не понимаешь как оно работает и для чего.
M>Масштаб одной из проблем, согласись, несколько уменьшился, не?
Не.
M>Кстати, а что за проблема "off-by-1 errors"? https://en.wikipedia.org/wiki/Off-by-one_error
M>>>Ну, у меня домашняя бухгалтерия — она такая, "домашняя". Как минимум, сотые доли копеек очень в ходу. И проблем там на самом деле выше крыши. Например, "банковское" округление придумали не для того, чтобы на ровном месте новых проблем изобрести. M>·>Ну в сотых копейках, не важно. Важно что арифметика целочисленная в бухгалтерии. M>Ну они таки делят. Уже известен способ целочисленного деления без потерь знаков?
Целочисленное деление по определению работает без потерь знаков — их там нет, терять нечего.
Например, в налоговой декларации делишь между N участниками — один из них помечается специальным образом, кому идут остатки. Т.е. 100 / 3 == 33 + 33 + 34.
M>>>Ну, у меня я бы не сказал, что точка фиксированная. Вполне себе плавает. Фикс точка — это когда, например, берем int64_t, и говорим, что младшие 32 бита — дробная часть, старшие — целая часть. У меня вполне себе точка плавающая, просто я не упаковался в фиксированный размер представления. Тут интересно вообще, как такое представление назвать? Не фикс — явно, но и не привычная плавучка — тоже. Надо наверно как-то отдельно называть такой способ представления чисел. M>·>Нет, фиксированная точка это когда ты явно хранишь фиксированное число знаков после запятой. M>Ну, хз. Про фиксированную точку 99% публикаций — о тех случаях, когда точка прибита гвоздями. А оставшийся 1% я не видел
Как минимум "во многих СУБД — NUMBER(M,N)"? Разве не оно? Или я не понял что значит прибитость гвоздями в твоём понимании.
M>·>Притом знаки могут быть как двоичные (double), M>double — это вроде не про фиксированную точку
Да, я имел в виду это про двоичную точнку. Тут четые комбинации — плавающая|фиксированая * двоичная|десятичная.
M>·>так и десятичные (java.lang.BigDecimal или аналог какой-нибудь). А в int64 или byte[] — это уже детали реализации. int64 просто ограничивает тем, что ты не можешь хранить больше, чем 18 десятичных знаков. M>Ну вот я просто и запилил аналог java.lang.BigDecimal. Ни в плюсах, ни в кути — почему-то нет. Хотя вроде Qt умеет в базы данных, а во многих СУБД — NUMBER(M,N) — вполне родной формат. Почему до сих пор не сделали — я хз. Вот я это и исправил, как минимум, для себя. https://en.wikipedia.org/wiki/List_of_arbitrary-precision_arithmetic_software
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
M>>А у меня можно и 3.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042 и ничего не потеряется. ·>Нигде ничего "не теряется", а отбрасывается. Оно у тебя теряется если ты не понимаешь как оно работает и для чего.
У меня ничего не теряется и не "отбрасывается". Умножь 123456789012345678901234567890.12345678901234567890 на 0.000000000000000000000000000000000000000000000000000000000000001
Я могу получить точный результат, а ты — нет.
M>>Масштаб одной из проблем, согласись, несколько уменьшился, не? ·>Не.
А...
Но вообще-то можно было привести ссылку на русскую вики. Или даже словами рассказать. Проблема старая, да, а с итераторами ещё сложнее становиться.
·>Целочисленное деление по определению работает без потерь знаков — их там нет, терять нечего. ·>Например, в налоговой декларации делишь между N участниками — один из них помечается специальным образом, кому идут остатки. Т.е. 100 / 3 == 33 + 33 + 34.
Расскажи об этом бухгалтерам. А то для них дураков придумали банковское округление, и они по тупости трахаются с дебетом-кредитом, даже если все честно проводилось.
M>>Ну, хз. Про фиксированную точку 99% публикаций — о тех случаях, когда точка прибита гвоздями. А оставшийся 1% я не видел ·>Как минимум "во многих СУБД — NUMBER(M,N)"? Разве не оно? Или я не понял что значит прибитость гвоздями в твоём понимании.
Прибитость — это когда ты в компайл-тайме говоришь, где целая, где дробная часть
M>>·>так и десятичные (java.lang.BigDecimal или аналог какой-нибудь). А в int64 или byte[] — это уже детали реализации. int64 просто ограничивает тем, что ты не можешь хранить больше, чем 18 десятичных знаков. M>>Ну вот я просто и запилил аналог java.lang.BigDecimal. Ни в плюсах, ни в кути — почему-то нет. Хотя вроде Qt умеет в базы данных, а во многих СУБД — NUMBER(M,N) — вполне родной формат. Почему до сих пор не сделали — я хз. Вот я это и исправил, как минимум, для себя. ·>https://en.wikipedia.org/wiki/List_of_arbitrary-precision_arithmetic_software
Ни в стандарте C++, ни в Qt — ничего такого нет. Я запилил своё. У тебя есть какие-то возражения?
Здравствуйте, Marty, Вы писали:
M> M>>А у меня можно и 3.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042 и ничего не потеряется.
M> ·>Нигде ничего "не теряется", а отбрасывается. Оно у тебя теряется если ты не понимаешь как оно работает и для чего. M> У меня ничего не теряется и не "отбрасывается". Умножь 123456789012345678901234567890.12345678901234567890 на 0.000000000000000000000000000000000000000000000000000000000000001
Это абстрактные цифры. Без бизнес-требований. Поэтому смысла не имеет.
M> Я могу получить точный результат, а ты — нет.
А толку от этого результата?
M> M>>Масштаб одной из проблем, согласись, несколько уменьшился, не? M> ·>Не. M> Вай?
Потому что появляются другие проблемы, которые не проще, а даже сложнее. Т.к. отбрасывать надо в любом случае.
M> ·>Целочисленное деление по определению работает без потерь знаков — их там нет, терять нечего. M> ·>Например, в налоговой декларации делишь между N участниками — один из них помечается специальным образом, кому идут остатки. Т.е. 100 / 3 == 33 + 33 + 34. M> Расскажи об этом бухгалтерам. А то для них дураков придумали банковское округление, и они по тупости трахаются с дебетом-кредитом, даже если все честно проводилось.
Ну хорошие бухгалтеры это и так знают. А плохим да, приходится рассказывать.
M> ·>Как минимум "во многих СУБД — NUMBER(M,N)"? Разве не оно? Или я не понял что значит прибитость гвоздями в твоём понимании. M> Прибитость — это когда ты в компайл-тайме говоришь, где целая, где дробная часть
Ну в субд значит нет прибитости. Хотя по сути на практике компайл-тайма часто хватает, т.к. нередко бизнес устраивает, скажем 8 точек после запятой и никого нанодоллары не интересуют.
M> ·>https://en.wikipedia.org/wiki/List_of_arbitrary-precision_arithmetic_software M> Ни в стандарте C++, ни в Qt — ничего такого нет.
В boost вроде как есть, почти стандарт.
M> Я запилил своё. У тебя есть какие-то возражения?
Нет.
Здравствуйте, ·, Вы писали:
M>> M>>А у меня можно и 3.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042 и ничего не потеряется.
M>> ·>Нигде ничего "не теряется", а отбрасывается. Оно у тебя теряется если ты не понимаешь как оно работает и для чего. M>> У меня ничего не теряется и не "отбрасывается". Умножь 123456789012345678901234567890.12345678901234567890 на 0.000000000000000000000000000000000000000000000000000000000000001 ·>Это абстрактные цифры. Без бизнес-требований. Поэтому смысла не имеет.
Так и претензии твои тоже без "бизнес-требований"
И?
M>> M>>Масштаб одной из проблем, согласись, несколько уменьшился, не? M>> ·>Не. M>> Вай? ·>Потому что появляются другие проблемы, которые не проще, а даже сложнее. Т.к. отбрасывать надо в любом случае.
Было бы интересно узнать об этих проблемах
M>> Расскажи об этом бухгалтерам. А то для них дураков придумали банковское округление, и они по тупости трахаются с дебетом-кредитом, даже если все честно проводилось. ·>Ну хорошие бухгалтеры это и так знают. А плохим да, приходится рассказывать.
То есть существование проблемы ты не отриаешь? Ну, уже хорошо
M>> ·>Как минимум "во многих СУБД — NUMBER(M,N)"? Разве не оно? Или я не понял что значит прибитость гвоздями в твоём понимании. M>> Прибитость — это когда ты в компайл-тайме говоришь, где целая, где дробная часть ·>Ну в субд значит нет прибитости. Хотя по сути на практике компайл-тайма часто хватает, т.к. нередко бизнес устраивает, скажем 8 точек после запятой и никого нанодоллары не интересуют.
Есть прибитость в рантайм. А про нанодоллары ты расскажи тут —
Здравствуйте, Marty, Вы писали:
M>Без теории, так-то, особого смысла считать нет — хрень насчитаешь, обязательно что-нибудь либо сойдётся не там, где должно, либо разойдётся там, где не должно, и пр
Были два понятия, сходимость и устойчивость и на них мы действительно много времени тратили.
Но я учился в конце совка и выпускники ФПМ тогда всей толпой в военку работать шли (отсюда у нас и стипендия повышенная была и государство серьезно к прикладной математике относилось).
В военке в те времена нужно было много чего считать и правильно.
Программирование же у нас было хоть и приличное, но оно шло вторым планом относительно собственно прикладной математики.
Ну а без пониманиря особенностей вычислений на компьтерах в численный методах никак.
Здравствуйте, Marty, Вы писали:
M>У меня ничего не теряется и не "отбрасывается". Умножь 123456789012345678901234567890.12345678901234567890 на 0.000000000000000000000000000000000000000000000000000000000000001 M>Я могу получить точный результат, а ты — нет.
Зачем он тебе и что с ним делать?
M>Расскажи об этом бухгалтерам. А то для них дураков придумали банковское округление, и они по тупости трахаются с дебетом-кредитом, даже если все честно проводилось.
Да не нужно в жизни банковское округление. Тем более тем, кто трахаются с дебетом-кредитом. В статистике, да это один из способов уменьшения погрешности, не самый лучший.
Те кто "трахаются с дебетом-кредитом" работают всегда с целыми копейками (ну может с сотыми долями цента, иногда на американский манер если). И никакое "банковское" округление им не нужно. А то, что оно по умолчанию у американцев, так это такой их таракан, наподобие кантри-музыки и пива пинтами.
Здравствуйте, Marty, Вы писали:
M>>> У меня ничего не теряется и не "отбрасывается". Умножь 123456789012345678901234567890.12345678901234567890 на 0.000000000000000000000000000000000000000000000000000000000000001 M>·>Это абстрактные цифры. Без бизнес-требований. Поэтому смысла не имеет. M>Так и претензии твои тоже без "бизнес-требований" M>И?
Мои претензии как раз в том, что ты не озвучил никаких бизнес-требований и вдруг заявляешь "ничего не потеряется", как будто это какое-то вечное благо и так и надо делать. Это, как раз, бОльшая проблема. За исключением каких-то редких академических задач, 100500 знаков после запятой никому не нужны.
M>>> ·>Не. M>>> Вай? M>·>Потому что появляются другие проблемы, которые не проще, а даже сложнее. Т.к. отбрасывать надо в любом случае. M>Было бы интересно узнать об этих проблемах
Нет такой проблемы, чтобы ничего не терялось. Проблема как раз в том, чтобы решить когда и как и что отбрасывать.
M>>> Прибитость — это когда ты в компайл-тайме говоришь, где целая, где дробная часть M>·>Ну в субд значит нет прибитости. Хотя по сути на практике компайл-тайма часто хватает, т.к. нередко бизнес устраивает, скажем 8 точек после запятой и никого нанодоллары не интересуют. M>Есть прибитость в рантайм. А про нанодоллары ты расскажи тут —
Здравствуйте, Vzhyk2, Вы писали:
H>>Забудь про «==« для плавающей точки. Только разницу с эпсилон сравнивай V>Чушь. Всё зависит от того, что именно ты хочешь сделать и где.
В общем случае да, на практике использование == для плавучки — это или из-за незнания как правильно работать с машинной арифметикой или какой-то трюк, хак в конкретном месте.
Здравствуйте, Michael7, Вы писали:
M>Здравствуйте, Kazmerchuk Pavel, Вы писали:
KP>>Решение уже привели. Задача шагать по сеточной функции, точно попадая в узлы. Узлы подвижны.
M>Тогда лучше узлы нумеровать целочисленными значениями и шагать инкрементами, а координаты вычислять.
Что значит шагать инкрементами? Шаги и между узлами попадают.
M>>Тогда лучше узлы нумеровать целочисленными значениями и шагать инкрементами, а координаты вычислять. KP>Что значит шагать инкрементами? Шаги и между узлами попадают.
Если у тебя сетка какая-то, то есть ее топология в виде узлов. Вот и предусмотреть нумерацию исключительно индексами i,j,k — как-то так. Может быть с дополнительным параметром отступа от узла или что-то в этом роде. Если же нужно именно проверять куда попал какой-то шаг, то все же сравнивать надо не == а с погрешностью. abs(a-b)<epsilon
Здравствуйте, Kazmerchuk Pavel, Вы писали:
KP>Что значит шагать инкрементами? Шаги и между узлами попадают.
Количество узлов фиксированное для одной модели?
Здравствуйте, Michael7, Вы писали:
M>Здравствуйте, Kazmerchuk Pavel, Вы писали:
M>>>Тогда лучше узлы нумеровать целочисленными значениями и шагать инкрементами, а координаты вычислять. KP>>Что значит шагать инкрементами? Шаги и между узлами попадают.
M>Если у тебя сетка какая-то, то есть ее топология в виде узлов. Вот и предусмотреть нумерацию исключительно индексами i,j,k — как-то так. Может быть с дополнительным параметром отступа от узла или что-то в этом роде. Если же нужно именно проверять куда попал какой-то шаг, то все же сравнивать надо не == а с погрешностью. abs(a-b)<epsilon
Есть функция (сеточная), заданная значениями в некоторых точках (узлах). Количество и расположение узлов произвольное. Есть система дифференциальных уравнений (ДУ), которая интегрируется численным методом. Правые части системы ДУ зависят от сеточной функции. Численный метод получает на вход в том числе шаг (по времени). Длинна шага каждый раз вычисляется исходя и требуемой точности интегрирования. Проблема в том, что сеточная функция имеет разрывы в узлах. Если метод интегрирования не попадает в точки разрыва, он теряет точность. Я вычисляю шаг до следующего узла (как написали выше) и ошибку. Если ошибка нулевая — попадем точно в узел, всё ОК, если нет, корректирую шаг чтобы гарантировано не "перепрыгнуть" узел.