[Прим. пер.: на Хабре уже был перевод этой статьи, но незавершённый примерно на четверть.]

Неправда.

Калькулятор должен показывать результат введённого математического выражения. А это намно-о-ого сложнее, чем кажется.

В этом посте я расскажу величайшую историю о разработке приложения-калькулятора.

На изображении выше показан калькулятор из iOS.

Заметили что-нибудь?

Он посчитал неправильно.

(10100) + 1 − (10100) равно 1, а не 0.

Android считает правильно. А причина, по которой он это делает, абсолютно безумна.

Google нанял Ханса-Юргена Бёма, знаменитого созданием «сборщика мусора Бёма» (Boehm garbage collector). Компании нужен был элитный кодер, способный решить проблемы сборки мусора и параллельного программирования. Он возглавил проект по разработке семантики разделяемых переменных C++. Но потом Google дал ему задачу, которую невозможно решить: создание приложения-калькулятора.

Наверно, даже для него это было сложно.

Задача калькулятора — давать правильные ответы. Числа с плавающей запятой неточны — они не могут представить 0,3 или 10100. То есть создание калькулятора на основе чисел с плавающей запятой похоже на строительство дома на песке.

Наверно, это стоит объяснить подробнее: чтобы давать правильные ответы математических выражений, калькулятор должен обрабатывать числа.

Но почти никакие числа невозможно выразить в стандарте чисел с плавающей запятой IEEE.

Для получения точных ответов при даже самых простых операциях с такими числами требуется тщательно всё продумывать.

Некоторых проблем можно избежать, если пользоваться арифметикой с произвольной точностью (bignum-арифметикой).

Большинство числовых типов всегда имеют длину 2 или 4 байта. Но с bignum всё не так. Это безграничные целые числа, которые при необходимости разрастаются в памяти.

Это решает проблему с примером (10100) + 1 - (10100). Но bignum — это целые числа. А как же насчёт дробей?

Проблема дробей легко решается: достаточно использовать bignum для числителя и знаменателя. Реализация арифметических операций с такими типами тривиальна и всегда даёт точные ответы.

На этом многие бы начали праздновать победу. Но Бёма это не удовлетворило.

Математика — это далеко не только одни дроби. Как насчёт π или √2? Калькулятор, построенный на основе дробей с произвольной точностью, не сможет вычислить длину окружности, потому что π нельзя выразить в виде дроби.

Если калькулятор не способен справиться с математикой девятого класса школы, то кому он нужен?

Приблизиться к решению Бёму позволила алгебраическая арифметика.

Забудьте о представлении чисел в виде числителей и знаменателей.

Можно представить их в виде степенного уравнения.

Для √2 это будет x² - 2 = 0. (Плюс необходимо хранить информацию, что нам нужен только положительный корень.)

Теперь математические операции реализовать будет сложнее:

  • Для сложения нужно создать новый многочлен, корень которого является суммой слагаемых

  • Для умножения нужно использовать композицию многочленов и результанты

И знаете что? Бёму всё равно этого было недостаточно. Это сработает только с алгебраическими числами, но не с π. Поэтому Бёму не оставалось ничего другого, кроме как ещё глубже закапываться в проблему.

Мы начали с целых чисел (bignum), перешли к рациональным числам, затем к алгебраическим. Что дальше?

Конструктивные вещественные числа.

Так Бём начал исследовать «рекурсивную вещественную арифметику» (recursive real arithmetic, RRA). Для выражения и указанной точности RRA позволяет получить ответ как минимум с этой точностью.

Посмотрите на обложку этого старого учебника. Видите, что линейки становятся всё меньше и меньше?

Конструктивные вещественные числа — это такие числа, которые можно вычислять со всё большей и большей точностью.

Мы никогда не сможем перечислить все цифры после запятой в π. Но если я спрошу рациональное число на расстоянии не больше 0,01 от π, то вы назовёте 3,14.

π находится в пределах 0,01 от 3,14, так что это правильный ответ.

Допустим теперь, что я спрошу число на расстоянии 0,01 от 2π.

Вы знаете, как получать цифры π после запятой (3,14159...).

Можно умножить их на 2. Но сколько разрядов нужно взять, чтобы ответ точно был в окрестности 0,01 от 2π?

Умножение числа на 2 удваивает погрешность. Я спросил число в окрестности 0,01 от 2π, поэтому нам нужна аппроксимация π в окрестностях 0,005.

Допустим, вы получили 3,141, что и в самом деле находится на расстоянии меньше 0,005 от π. Умножим его на 2 и готово!

Так и работает RRA.

Каждое число в RRA представлено в виде функции, получающей рациональное число и возвращающей рациональное число.

Получаемое им рациональное число — это требуемый допуск.

Возвращаемое рациональное число гарантированно находится в пределах допуска представляемого им вещественного числа.

Благодаря этому RRA легко использовать. Вы говорите, насколько точным должен быть ответ, а она рекурсивно определяет необходимую точность во всех промежуточных вычислениях.

Она без проблем может работать с выражениями, где есть π или √2. А калькулятору без этого не обойтись.

Вы, наверно, думаете, что Бём на этом остановился?

В качестве «точности вывода» он указал количество разрядов калькулятора, ведь так?

Тогда все отображаемые на калькуляторе разряды будут правильными, а значит, теперь он всегда будет показывать правильный ответ! Ведь так?

Не будем торопиться. Когда пользователь вводит «1-1», то ответом должен быть 0, поэтому мы хотим показать «0».

Однако RRA только сообщит нам, что «1-1 находится в пределах погрешности округления 0,0000000000000»

Если показывать на экране 0,0000000000000, когда ответ равен 0, то это будет ужасно с точки зрения UX.

Бём снова вернулся к анализу. Наверно, он уже был сильно озадачен. По сравнению с этой проблемой его «эффективно использующая пространство консервативная сборка мусора» казалась детской забавой.

В одиночку он бы не справился, поэтому призвал на помощь своих коллег, например Роберта Картрайта и Вернона Ли

Роберт Картрайт
Роберт Картрайт

Мы можем проверить два RRA-числа на неравенство. Можно вычислять их со всё большей и большей точностью, пока мы не увидим, что они различаются.

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

Вспомним, что если калькулятор покажет 0 как ответ выражения e-10000, то это будет неверно. Он должен показать 0,00000... и позволить вам проскроллить все нули, чтобы найти, где появляются другие значения. Но он ДОЛЖЕН показывать 0 при вводе sin(π), потому что sin(π) точно равен 0. RRA никак не позволяет нам определить, что sin(π) точно равен 0. Или можно просто не давать ответ, как это делает калькулятор iOS:

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

А именно:

  1. Четырьмя базовыми арифметическими операциями и квадратными корнями.

  2. Тригонометрическими функциями sin, cos и tan, а также обратными им функциями.

  3. Степенными функциями и (натуральными) логарифмами

Это гораздо меньшее множество чисел, чем все конструктивные вещественные. И оказалось, что другие люди уже исследовали именно эту задачу. Их звали Дэн Ричардсон и Джон Фитч. Они решили её в 1994 году.

Их решение было абсолютно корректным, за исключением случаев, когда одно из чисел оказывается контрпримером гипотезы Шануэля.

Но на самом деле такого никогда не случится.

Гипотеза Шануэля — одна из важнейших в теории чисел, и пока никто не нашёл для неё контрпримера.

Похоже на идеальное решение. Но есть лишь одна проблема: оно слишком медленное.

1 не равно 1 - e(-e^1000). Но чтобы это определил алгоритм Ричардсона и Фитча, потребуется больше этапов, чем атомов во Вселенной. Нужно было придумать что-то более быстрое. Изначально Бём с коллегами ставили задачу определения равенства двух конструктивных вещественных чисел. А её решить невозможно. Они упростили её и приблизились к решению, ограничив способы конструирования чисел. Это сделало задачу решаемой, но медленно.

Можно ли ещё раз упростить её?

Они поняли, что нет ничего особо страшного в том, чтобы показывать «0,000000...» в случае, когда ответ равен 0, хоть это и неидеальный UX. Нельзя лишь показывать «0» в случае, когда ответ 0,0000001.

Может быть, есть какой-то более быстрый консервативный алгоритм?

И они придумали нечто поистине великолепное.

RRA даёт нам всю мощь конструктивных вещественных чисел, но имеет один недостаток: с её помощью невозможно получить точные ответы. Рациональная арифметика даёт точные ответы, но не может выразить π. Можно ли объединить их сильные стороны?

Разработчики осознали, что если пользователь просто вводит 6 * 9 или 8 / 3, то полная мощь RRA не требуется, достаточно рациональной арифметики. RRA нужна только в случаях, когда рациональных чисел недостаточно. Можно использовать её, когда в дело вступают числа наподобие π или √2, а в остальных случаях применять рациональные числа

Рациональные числа точны, но в них нельзя выразить π.

RRA-числа могут описывать числа наподобие π, но не могут быть точными.

Разработчики придумали такое решение: представлять каждое число как рациональное, умноженное на RRA-число. Но этого недостаточно. Как только в дело вступают RRA-числа, результат обязательно становится неточным.

Но даже в случае иррациональных чисел RRA иногда может быть излишней.

RRA представляет π в виде функции, способной возвращать рациональные числа, с произвольной точностью близкие к π. (Точно так же, как все RRA-числа представляются в виде функций)

Можно сказать: «Мне нужно число π с точностью 0,001», и RRA ответит: «это 3,141»

Иногда нам нужна RRA. Но на этот случай можно просто иметь особое представление π, которое мы будем особым образом использовать вместо её функции RRA. Мы называем это символьным представлением, поскольку это похоже на написание символа π вместо бесконечной последовательности чисел

Ага, дело пошло. А теперь давайте сделаем так не только для π. Очевидно, что нам нужно символьное представление вещественного числа 1. Но многие используемые нами иррациональные числа — это результат применения операции к рациональному аргументу. Для них можно тоже создать символьные представления.

Разработчики решили хранить символьные представления для √arg, eᵃʳᵍ, ln(arg), log₁₀(arg), sin(πarg), tan(πarg) и других функций (где arg — это какое-то рациональное число).

Итак, окончательное представление чисел выглядит так: рациональное, умноженное на вещественное, где вещественное — это или RRA-вещественное, или символьное вещественное.

Необходимо помнить, что фундаментальная проблема заключается в невозможности проверки RRA-чисел на равенство. Как только мы используем такое число, всё вычисление становится неточным, но иногда они необходимы. То есть Бёму и его коллегам достаточно было максимально избегать использования RRA-вещественных чисел!

Например, в (1 × π) + (3 × π) у нас, к счастью, есть символьные представления вещественных чисел. В обоих случаях это π.

Так как вещественные части одинаковы, мы можем выполнить суммирование, сложив рациональные части.

Если бы выражение имело вид (1 × π) + (3 × √2), то для вычислений мы бы использовали RRA.

Благодаря этому представлению разработчики добились баланса: все отображаемые на экране разряды всегда правильны и почти никогда не отображается больше разрядов, чем это необходимо.

«Система компьютерной алгебры» решила бы схожую задачу, но была бы гораздо медленнее и сложнее. Такая система настолько сложна, что её поддержкой на уровне продакшена способны заниматься очень немногие. А Бём и его коллеги придумали на 100% корректную систему, в 99% случаев обеспечивающую идеальный UX и ценой всего 1% сложности реализации.

Вот что называется настоящей разработкой ПО! Вам стоит прочитать статью Ханса-Юргена Бёма Towards an API for the Real Numbers.

Надеюсь, теперь вы больше будете ценить калькулятор в Android!

Комментарии (113)


  1. sirri
    18.02.2025 08:53

    А это что же тогда? https://habr.com/ru/articles/883028/


    1. PatientZero Автор
      18.02.2025 08:53

      Неполный перевод оригинала


      1. sirri
        18.02.2025 08:53

        Так Вы бы где-нибудь в начале это указали.


        1. PatientZero Автор
          18.02.2025 08:53

          Да, добавил комментарий


      1. Xobotun
        18.02.2025 08:53

        Спасибо вам за полный перевод. Вашу версию ещё и читать приятно; в той я регулярно глазами о шероховатости спотыкался. :)


        1. PatientZero Автор
          18.02.2025 08:53

          Спасибо)


  1. Zenitchik
    18.02.2025 08:53

    В реальной жизни такие большие числа не бывают такими точными. Поэтому 0 - правильный ответ.

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


    1. unreal_undead2
      18.02.2025 08:53

      Видимо, для гугла было принципиально точно обрабатывать числа порядка гугла )


      1. PrinceKorwin
        18.02.2025 08:53

        Это вы про недавний штраф?..


  1. goldexer
    18.02.2025 08:53

    А потом мы видим множество споров под простым 6÷2(1+2) и два калькулятора (один из которых инженерный, а второй студенты писали), показывающих разные ответы. Никто не вдается в подробности, почему именно знак перед скобкой опущен. Просто что-то такое смутно помнят со школы, мол, раз знака нет, значит умножение, а раз умножение, значит по порядку и решаем. Арифметика или алгебраика - не всё ли равно им? Представляете, даже такой простой пример, показывает, что перед тем как позволить пользоваться калькулятором, людям надо вручить ещё и инструкцию к нему. Да-да, из того же разряда, что и «сушить кошку в микроволновке запрещено». Так что да, написать грамотный калькулятор - весьма непростая задача... Благодарю за статью и пойду открою окно, а то надушнил вам тут)))


    1. stanislavskijvlad
      18.02.2025 08:53

      6÷2(1+2)

      Тут всё (не)просто. Во-первых, есть раннее или строгое(сильное) связываение. 2a — это два А, а не просто А два раза. Потому что 2а/2а = 1 , а не а². Понимаете ? Во-вторых, в дробях всё, что числитель — это одно, а всё, что знаменатель — это другое. Дроби крутые сами по себе, а с рядами Тейлора/Фурье/Маклорена так просто мега имба. И можно было бы определить знак / как последовательное деление, а ÷ (обелюс) сделать знаком дроби в линейной записи. Точки обозначали бы числитель и знаменатель. Тогда 6÷2(1+2) становится (6)÷(2(1+2)). Ну и третье. Обратная польская нотация решает и даёт одназначность толкования. Писали же про стековый калькулятор. Автор ещё уточнил, что особенно любит их.


      1. whitedog36
        18.02.2025 08:53

        Что за бред...

        2a – это просто другая запись 2×a. И из-за другой записи приоритет не меняется.

        И не надо выдумывать, что было бы по-другому, то было бы круто.


        1. VBDUnit
          18.02.2025 08:53

          Есть две разных нотации, ЕИНИП. В одной трактуется как простое 2×a, в другой эта операция трактуется как умножение с повышенным приоритетом. И, в зависимости от того, как человека выучили, он будет трактовать это так или иначе. Поэтому люди и спорили.


        1. khajiit
          18.02.2025 08:53

          Чтобы не было бреда, надо, во-первых, даже денормализованные дроби записывать правильно. Во-вторых: явно указывать приоритеты скобками.

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



      1. Tyusha
        18.02.2025 08:53

        6÷2(1+2)

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


        1. Zenitchik
          18.02.2025 08:53

          Я бы сразу спросил, на каком это языке. Потому что я не знаю ни одного языка, в котором эта запись была бы валидным выражением.


    1. NVVI
      18.02.2025 08:53

      Для некоторых математических выражений (типа 6÷2(1+2)) в принципе не существует однозначной интерпретации. В Википедии есть несколько абзацев на эту тему. Что-то типа undefined behaviour в языках программирования.


      1. Aleshonne
        18.02.2025 08:53

        Да просто последовательность символов «6÷2(1+2)» не является математическим выражением, хотя и состоит из знаков, которые обычно используют для написания таковых. Это аналогично тому, что не любая комбинация операторов языка программирования является компьютерной программой.


    1. karavan_750
      18.02.2025 08:53

      6÷2(1+2)

      На эту тему Борис Трушин достаточно емко сказал.

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


      1. VBDUnit
        18.02.2025 08:53

        понимается

        Кем? :) Получается, на математичность влияет субъективный фактор — если человек не в курсе, что это выражение можно интерпретировать хотя бы двумя разными способами, то для него оно математическое, а для того, кто знает — не математическое.

        И тогда получается, что математики видят в нем не математическое выражение, а не математики — математическое. Свой среди чужих, чужой среди своих. Забавно.


        1. karavan_750
          18.02.2025 08:53

          Кем? :) Получается, на математичность влияет субъективный фактор — если человек не в курсе, что это выражение можно интерпретировать хотя бы двумя разными способами, то для него оно математическое, а для того, кто знает — не математическое.

          И тогда получается, что...

          ...Что ограниченность мышления даёт свои сайд-эффекты :)


    1. ahabreader
      18.02.2025 08:53

      Какой-то бред. Это как позвонить в Labcenter Electronics и объяснить им, сколько раз и где именно они нарушили ЕСКД.

      Противопоставляет алгебру и арифметику советское пособие для педагогов. Оно утверждает, что в алгебре "знак умножения связывает компоненты действия сильнее, чем знак деления" (зависимо от того, опускается ли знак): a ÷ bc = a ÷ b*c = a÷(b*c). При этом само дальше эту сомнительную практику не использует и делит горизонтальной чертой.

      В одних калькуляторах Texas Instruments решили повысить приоритет неявного умножения. На правила алгебры TI не ссылалась. Затем в следующих калькуляторах это решение откатили. В рунете повышение приоритета приписали некой алгебраичности калькулятора. Обосновывают тем пособием и ещё одним, противоречащим ему (пофиг, пляшем).

      Общего правила в калькуляторах нет, один производитель в двух соседних моделях может поменять решение (TI-82 и TI-83), заучивать это не сильно полезнее, чем способы извлечения корня на арифмометре.

      И подкину на эту тему:

      • На письме можно не дотянуть до конца черту корня: √ax, пусть гадают.

      • 3*10^6 - это форма записи одного числа (то же, что 3e6) или выражение из нескольких чисел? От этого зависит результат выражения 1/3*10^6. Wolfram Alpha считает одним числом (но не с пробелами: 3 * 10^6), при обсуждении предыдущей статьи на это наткнулся.


      1. Refridgerator
        18.02.2025 08:53

        В одних калькуляторах Texas Instruments решили повысить приоритет неявного умножения

        Я тоже так делал. А ещё ввёл оператор умножения с приоритетом ниже сложения, и с 2-мя дополнительными операторами делениями аналогично. Всё это для того, чтобы аргументы функции без скобочек писать можно было. Но вот операция возведения в степень ^ в эту стройную систему уже не вписалась, увы.


      1. stanislavskijvlad
        18.02.2025 08:53

        Имхо, человек - не робот, и мне запись a ÷ bc = a÷(b*c) кажется логичной. Но a ÷ b*c воспринимается как что-то отдельное. Хотя даже здесь, признаюсь, глазами b*c выглядит как целое, без скобок. Нам (людям) договориться бы один раз и всё.


  1. sirri
    18.02.2025 08:53

    Уж не помню где (то ли в книжках, то ли на обучающих сервисах-сайтах), но встречал фразу "а потом в процессе изучения мы с вами напишем простую программу-калькулятор" ;)


    1. kos_s
      18.02.2025 08:53

      Но в этих книжках же не писали, что этим простым калькулятором потом будет пользоваться кто-то еще.


    1. qenoamej
      18.02.2025 08:53

      Тоже такое проходил, только там не было скобок и даже запятых, только целые числа, сложение, вычитание, умножение, деление, ввод только с кнопок, без клавиатуры, только одна операция за раз.

      И нельзя было выполнять действия над предыдущим результатом, только ввод новых целых чисел.

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


    1. DennisP
      18.02.2025 08:53

      Эти калькуляторы из примеров или могут выполнять только по одному действию за раз, или полагаются на имеющийся в ЯП оператор eval или его аналог


  1. S_WW
    18.02.2025 08:53

    Фигнёй какой-то занимались все эти люди. Какое такое π? Пользователь не вводит на калькуляторе π, он вводит некие цифры. Вот сколько он их ввёл, с этим числом и будут выполняться вычисления. А вовсе не с числом π.


    1. konst90
      18.02.2025 08:53

      Пользователь может ввести именно pi, специальной кнопкой. А не набирать 3,141592...


      1. p07a1330
        18.02.2025 08:53

        Но у Пи в компе все равно же конечная точность?


        1. anka007
          18.02.2025 08:53

          Да, конечная. Но вы в курсе накапливаемой ошибки? Так что для констант, чтобы минизировать эту самую ошибку, точность должна быть весьма большой. А пи и е слишком часто встречающиеся константы при инженерных вычислениях.


          1. S_WW
            18.02.2025 08:53

            Значит надо взять на две цифры больше, чем требуется в результате. Собственно, так и построены все калькуляторы - у них обычно не меньше 6 цифр. А в инженерных расчётах требуется не больше трёх - да, представьте себе! 0.1% - такую точность обычно имеют хорошие измерительные приборы. Для особо точных может потребоваться четыре цифры. Вот поэтому шести цифр на калькуляторе за глаза хватает для любых расчётов. И поэтому данная статья - не более чем словоблудие!


            1. netch80
              18.02.2025 08:53

              Значит надо взять на две цифры больше, чем требуется в результате.

              Рекомендуем таки прочитать статью.

              Потому что именно сколько требуется в результате - там не фиксировано ни с написания кода калькулятора, ни даже с начала задания аргументов для расчёта.


            1. anka007
              18.02.2025 08:53

              Чтоб ваши финансы с такой точностью считали. Этого же достаточно?


            1. discipuli
              18.02.2025 08:53

              0.1% на самом деле не такая уж и большая точность

              То есть да, в классических инженерных расчётахт даже такая точность может быть избыточна, но например в каких нибудь научных расчётах или в определении времени это может быть критично, ближайший пример детектор гравитационных волн


              1. anka007
                18.02.2025 08:53

                Ближайший пример - расчет процентов по вкладу или налогам. 0.1% это вообще днище, а не точность. И это то, с чем сталкивается почти каждый человек. Пи в этом не участвует, но это такой маркер как разработчик вообще относится к точности расчетов.


        1. Pshir
          18.02.2025 08:53

          В статье же дан ответ на этот вопрос: зависит от конкретного выражения. sin(πn) даст в ответе точный ноль - в данном конкретном случае π фактически имеет бесконечную точность. А если считать π+e, например, то точность будет конечная.


          1. p07a1330
            18.02.2025 08:53

            Вы хотите сказать, что точность может превышать размерность разрядов, в которых число храниться?
            Условно если под хранение Pi выделено 32 бита память, он в любом случае будет иметь точность не больше, чем +-100/(2^33)%
            Даже если там применяется арифметика с плавающей запятой


            1. amphasis
              18.02.2025 08:53

              Эх, если бы вы всё-таки прочитали статью, вы бы не задавали сейчас этот вопрос...


            1. acsent1
              18.02.2025 08:53

              Так у них π хранится в виде функции. Поэтому и точность у него любая заданная


            1. Politura
              18.02.2025 08:53

              У вас телефон - андроид? Если да, то запустите там калькулятор, нажмите на кнопку Пи, он вам покажет начало этого числа. Начните его листать скролля пальцем справа налево, когда долистаете до конца, скажете нам, какая там конечная точность :)


              1. Keeper11
                18.02.2025 08:53

                У меня показывает 10 знаков после запятой, и дальше не скроллится.


                1. Politura
                  18.02.2025 08:53

                  Вероятно производитель вашего телефона предустановил какой-то другой калькулятор вместо гугловского. У дочки Моторола moto g, у жены Гугл пиксель 7, на обоих в калькуляторе скроллится бесконечно, доскроллил до 1000+ знака за несколько секунд.


                1. anka007
                  18.02.2025 08:53

                  А если например умножить на 10 000 000 000? Разные калькуляторы по разному себя ведут

                  MATE Calculator из убунты
                  MATE Calculator из убунты


            1. Pshir
              18.02.2025 08:53

              Именно это я и хочу сказать. Числа можно представлять разными способами. Возьмём число 0.1 - у вас же нет сомнений, что я смог абсолютно точно записал это число? А в двоичном представлении записать точно его невозможно. Но двоичное представление не является единственно возможным. Даже внутри компьютера вы можете, применив мозги, хранить не только двоичные числа. Именно об этом и написана статья.


        1. konst90
          18.02.2025 08:53

          Зависит от реализации. Можно забить константу, а можно считать с потребной точностью. Об этом, собственно, и статья.


        1. VBDUnit
          18.02.2025 08:53

          Технически можно впихнуть её не в виде данных, а в виде алгоритма, который бесконечно наращивает её точность. т. е. нажал равно — результат появился и начинает бесконечно уточняться, прямо на экране. Чем дольше ждёшь, тем точнее результат. И так можно не с π, а вообще со всеми числами — выражение сначала упрощается, а затем итеративно вычисляется, наращивая точность, до бесконечности.

          Если добавить возможность ставить на паузу вычисления уточнения и сохранять промежуточный результат на носитель, то получится калькулятор бесконечной точности.


          1. WalterBeech
            18.02.2025 08:53

            Никак не могу понять, для чего это нужно? Для чего может быть нужна точность π больше двух знаков после запятой? Если у калькулятора 6 разрядов, а в ответе все нули, а в седьмом — 1, то какая разница? Просто если первые 6 — нули, то выводить не "0.00000", а "0". Ну то есть как чисто теоретически интересная задача — написать идеальный калькулятор — я понимаю, а практически — для чего?


            1. VBDUnit
              18.02.2025 08:53

              интересная задача

              This.

              Вообще π может быть нужно с точностью больше 2 знаков, если мы делаем какую‑нибудь прецензионную втулку из рубина, у которой должна быть точность 1 атом. Да даже в пластины жестких дисков делаются с такой точностью, что двух знаков π явно мало, чтобы, например, рассчитать положение головки в полярных координатах.

              Калькулятор, который «абсолютно точный и не косячит, гарантия 100%» может быть действительно полезным, но далеко, далеко не всегда в этом есть необходимость. Но это не значит, что её вовсе нет.

              Кроме того, сам факт изучения вопроса «как сделать это очень точным» генерирует полезные знания и разные приёмы, которые могут помочь в тех местах, где практически нужно повысить точность или оптимизировать вычисления.

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


              1. WalterBeech
                18.02.2025 08:53

                Ок, насчёт винчестеров и т. п. — согласен. Но нужно ли это для калькулятора в ширпотребном устройстве за 15к рублей...


                1. Zenitchik
                  18.02.2025 08:53

                  Делать одинаковые программы легче, чем разные.


                1. anka007
                  18.02.2025 08:53

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


            1. Zenitchik
              18.02.2025 08:53

              Для чего может быть нужна точность π больше двух знаков после запятой?

              Чтобы после десяти действий накопленная ошибка округления всё ещё позволяла отличить эллипс от гиперболы.


            1. a-tk
              18.02.2025 08:53

              Для чего может быть нужна точность π больше двух знаков после запятой?

              Например, для траекторных вычислений космического аппарата в миссии на спутник Юпитера.


              1. anka007
                18.02.2025 08:53

                Я думаю имеется ввиду вычисления на калькуляторе. Безусловно есть сферы, где высокоточные вычисления в том числе π нужны. Но не в рамках же калькулятора.


                1. khajiit
                  18.02.2025 08:53

                  Игра для калькулятора Лунолёт


                  1. Zenitchik
                    18.02.2025 08:53

                    Человека видно по походке.


              1. WalterBeech
                18.02.2025 08:53

                И делать эти вычисления будем, конечно же, на андроидном калькуляторе!


            1. Pshir
              18.02.2025 08:53

              Представьте, что у вас в ответе на задачу возникла разность вида (π-3.14). Как вы думаете, 0 и 0.00159265... - это разные числа? Вам бы хотелось их отличать друг от друга?


    1. Pshir
      18.02.2025 08:53

      У Гугловского калькулятора есть режим инженерного калькулятора. И пользователь (я, например) не просто может ввести число π, он это регулярно делает. Зачем кому-то может понадобиться вводить вместо π некие цифры? Это и требует больше нажатий, и даёт заведомо неверный результат.


      1. S_WW
        18.02.2025 08:53

        Нажатие кнопки π приводит лишь к тому, что это конечное число цифр вводится калькулятором. Но оно от этого не перестаёт быть конечным.


        1. Politura
          18.02.2025 08:53

          Нет, в андроид калькуляторе число Пи (как и другие иррациональные числа) можно листать бесконечно, оно будет дорассчитываться налету.


          1. Fancryer
            18.02.2025 08:53

            У меня в Redmi 9 нельзя листать бесконечно, результат - 3,14159265.


            1. DaemonGloom
              18.02.2025 08:53

              Родной калькулятор в Samsung - ограничен 3,1415926536. Гугловский - бесконечен.


            1. Pshir
              18.02.2025 08:53

              Потому что это не гугловский калькулятор, а калькулятор Сяоми


        1. Pshir
          18.02.2025 08:53

          А вы не пробовали прочитать и понять статью, под которой вы комментарии оставляете? Или ваше изучение математики в школе остановилось в 6 классе?


  1. m_chrom
    18.02.2025 08:53

    Еще когда читал статью в оригинале, задумался над вопросм "А зачем это нужно было гуглу?". В чем смысл стрелять из пушки по воробьям, тратя дорогущее время топового специалиста (который потом вовлек еще двоих такого же уровня) на калькулятор, который 99% пользователей используют чтобы поделить чек в кафе?
    Ну, допустим, есть еще школьники с чуть более сложными вычислениями. Но все равно кажется, что описанное выше - это чудовищный оверкилл.


    1. Pshir
      18.02.2025 08:53

      Я бы просто радовался, что всё ещё есть люди, у которых есть желание и возможность сделать, как следует, а не как обычно. В наше время, когда школьники уже даже калькулятором разучиваются пользоваться и спрашивают ответ у произвольной LLM, это особенно ценно.


      1. m_chrom
        18.02.2025 08:53

        Это само собой! С точки зрения примера как основательно человек решал задачу, история максимально впечатляющая.


    1. greefon
      18.02.2025 08:53

      Есть два вида чудовищного оверкила:

      • Потратить очень много времени очень компетентного специалиста на написание идеального кода.

      • Потратить очень мало времени очень малокомпетентного специалиста и с помощью переиспользования кода быстро получить "рабочее" решение.

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

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


      1. m_chrom
        18.02.2025 08:53

        Согласен, симпатичнее. Но между этими оверкиллами есть и промежуточные решения.

        У меня вообще нет никаких вопросов к Бёму. Наверняка он получил кучу фана от процесса. Я, возможно, тоже на его месте так закопался бы (если бы умел делать это так же круто, как он).

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


        1. Pshir
          18.02.2025 08:53

          Скорее всего, его условным менеджером был кто-то из высшего руководства Гугла, и обосновывал эти затраты он перед собой :)


          1. Ugli
            18.02.2025 08:53

            "Значение числа Пи для человечества бесценно!"


        1. greefon
          18.02.2025 08:53

          Промежуточных решений не бывает. Бывают решения, удовлетворяющие ТЗ, и не удовлетворяющие. А вот ТЗ уже могут быть сформулированы "промежуточно".

          Что касается Бёма, то он занимался проблемой "калькулятора" задолго до прихода в Гугл, еще будучи сотрудником SGI (а затем HPE).

          Constructive Reals Calculator
          Constructive Real Arithmetic

          Together with Corky Cartwright, Vernon Lee, and others, I explored practical implementations of "exact" real computer arithmetic. Numbers are represented exactly internal to the computer, in a form that allows evaluation to any requested precision for display. This resulted in several papers and a sequence of implementations, including a Java one. It served as the basis of the more recent work on arithmetic in Google's Android calculator.



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


    1. Vytian
      18.02.2025 08:53

      Отцы-основатели Брин с Пэйджем -- математики в поколеньях, так что в давние времена империи добра оно было естественно. Ну или может их собственные финансы исчисляются с использованием той же библиотеки? Гугола денег у гугла, наверно, пока еще не предвидится, но когда считаешь свои деньги, даже одна мысль о принципиальной неточности гложет.


      1. m_chrom
        18.02.2025 08:53

        Ну или может их собственные финансы исчисляются с использованием той же библиотеки?

        Возможно, им просто нужно было как-то считать долг перед российскими телеканалами )))


    1. alamat42
      18.02.2025 08:53

      ИМХО, это вполне оправдано, с учетом того, что андроид имеет миллиарды пользователей. Если представить, что всего 1% пользователей считает на нём что-то сложнее, чем базовые операции, то 1% от миллиарда - это уже 10 млн людей.

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


      1. sic
        18.02.2025 08:53

        Это в сущности не сильно сложнее, чем заметка, это описывающая. В прочем, можно ещё куда проще - символьная оптимизация дерева вычислений (любое a x n + a x m равно a x (n+m) , при этом a мы считаем символом и даже не вычисляем, a^n/a^m = a^(n-m), и набор подобных правил) и трактовка последнего разряда любого вычисленного числа, как фантомного (любое x.000000000n равно x). Никто бы не придрался, если использовать 80 bit float. Контрпример можно придумать, но сложно и не особо нужно.


    1. vkni
      18.02.2025 08:53

      Но все равно кажется, что описанное выше - это чудовищный оверкилл.

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

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


      1. CitizenOfDreams
        18.02.2025 08:53

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

        Программист, нарисовавший интерфейс калькулятора для Win10: ваще пофиг.

        Скрытый текст


    1. gmtd
      18.02.2025 08:53

      У Гугла очень много денег и очень много понтов


      1. netch80
        18.02.2025 08:53

        Даже если это так, то описанное применение - правильно.


    1. netch80
      18.02.2025 08:53

      Вклад 1) в общее впечатление от гугла и андроида, 2) в мировую математику. Создание впечатления у тех, кто немного больше понимает, и тем самым хотя бы лёгкое склонение их на свою сторону.


    1. WalterBeech
      18.02.2025 08:53

      Вот-вот. И это та компания, которая на собеседовании задаёт специально вымученные вопросы про блендер, чтобы убедиться, что кандидат не будет делать over-thinking.


    1. yrub
      18.02.2025 08:53

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

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


    1. LightSUN
      18.02.2025 08:53

      задумался над вопросм "А зачем это нужно было гуглу?"

      Потому что гугл нанимает лучших профессионалов, а они [иногда] любят делать лучшее возможное решение.


  1. anoldman25
    18.02.2025 08:53

    Добавлю /поправлю.

    Конструктивные числа на самом деле это видимо вычислимые числа. См. википедию

    https://ru.wikipedia.org/wiki/Вычислимое_число

    Статья хилая, лучше смотреть английскую версию: https://en.wikipedia.org/wiki/Computable_number

    А еще лучше книгу "Верещагин Н. К., Шень А. — Лекции по математической логике и теории алгоритмов. Часть 3. Вычислимые функции — М.: МЦНМО, 1999 "

    Поучительное чтение, но требует некоторых мозговых усилий.

    P.S. Скачал из интернета, но там не хватает по крайней мере нескольких страниц в начале. Может печатная книга лучше? Не знаю.
    P.P.S. Похоже я ошибся. Но есть еще издание 2008, лучше наверное его почитать.


  1. igorlampo
    18.02.2025 08:53

    Даже чатгпт понял что правильный ответ 1


  1. Insaned
    18.02.2025 08:53

    Как-то так получилось что у меня установлено три приложения калькулятора для Linux - все три не сговариваясь дали правильный ответ на это (10^100) + 1 - (10^100)


    1. lazbaphilipp
      18.02.2025 08:53

      Ну если решение Бёма обнародовано, то уж кто-кто, а OS решения его точно у себя имплементируют.


    1. redfox0
      18.02.2025 08:53

      SpeedCrunch выдаёт неправильный ответ.

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


      1. redfox0
        18.02.2025 08:53

        (10^79) + 1 - (10^79)
        = 1

        (10^80) + 1 - (10^80)
        = 0


  1. codecity
    18.02.2025 08:53

    Надеюсь, теперь вы больше будете ценить калькулятор в Android!

    А вот что интересно. Ни в Android ни в iOS - не смогли сделать такую полезную штуку - как повтор последней операции при повторном нажатии на "=". А ведь часто такое нужно в быту, гораздо чаще чем супер-точность. А MS - смогли это сделать, молодцы.

    Причем сделать это не так уж тривиально на самом деле.


    1. blind_oracle
      18.02.2025 08:53

      У меня в Самсунге S21+ вполне повторяет во встроенном калькуляторе. Но, возможно, он не ванильный Андроидный...


      1. DaemonGloom
        18.02.2025 08:53

        Да, в Самсунге калькулятор сильно отличается от Гугловского.


  1. Asterris
    18.02.2025 08:53

    А как советский инженерный калькулятор считал и синусы и экспоненты в те годы, когда ещё не придумали IEEE для плавающей запятой?


    1. blind_oracle
      18.02.2025 08:53

      Брутально считал, по-советски :)


    1. Cheddar1789
      18.02.2025 08:53

      Внутри кгбшник проверял правильность вычислений)


    1. Zenitchik
      18.02.2025 08:53

      Форматы с плавающей запятой придумали сильно раньше, чем один из них был закреплён стандартом IEEE. И они были разные.


    1. netch80
      18.02.2025 08:53

      Вот вам исторический список только форматов представления плавучки: http://www.quadibloc.com/comp/cp0201.htm. Зацените разнообразие подходов и размеров.

      А ещё есть вопросы требований к вычислениям. IEEE754 требует для арифметики и рекомендует для функций - округление после как бы бесконечно точного результата. (На самом деле 1-2 младших бита, ULP, постоянно страдают - вот свежак про это. Но это таки начиная с sin() и для более сложных функций.) А раньше на это заметно поплёвывали.

      S/360, S/370, и их аналоги ЕС-10xx в родной плавучке (в современных доках она зовётся HFP, hexadecimal floating point) вообще усекали все числа в операциях, а сама HFP прыжками по 4 бита вместо 1 ещё больше портила. При переходе на них с 7090, 7094 стояли плач и скрежет зубовный. И ничего, на этом производились серьёзные расчёты... надо было, конечно, чуть серьёзнее учитывать погрешности операций, чем сейчас. В 1968-м был массовый отзыв на переделку, потому что в двойной точности не было вообще guard digit, и на вычитаниях с умножениями точность была неприлично низкой - IBM модернизировала все блоки. PDP-11 имела 2 защитных бита там, где надо 3, неуправляемое округление, не имела INF. Мы-то уже видим готовенькое, но научная и инженерная мысль тут развивалась чудовищно медленно.

      Те, кто профессионально занимаются вычислительной математикой всех видов, по крайней мере знают (их учили) про основные риски и методы их преодоления. Но тема неисчерпаема...


  1. Melichrone
    18.02.2025 08:53

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


    1. stanislavskijvlad
      18.02.2025 08:53

      Вот вам замечательный сайт:
      https://old.mipt.ru/online/#search.php?embedded=1

      И в частности: http://j90428as.beget.tech/course/Maths-RingsAndFields-15L.html


  1. Aleus1249355
    18.02.2025 08:53

    То есть Бёку и его коллегам

    Бёму же


  1. Fragster
    18.02.2025 08:53

    .


  1. SlFed
    18.02.2025 08:53

    Кроме двух иррациональных констант ( пи и е ) есть еще Фи или Золотая Пропорция. Как его выразить на таком калькуляторе ? Надо еще одну кнопку добавить.


    1. Ruimteschroot
      18.02.2025 08:53

      Ну золотая пропорция это алгебраическое число


    1. Pshir
      18.02.2025 08:53

      Золотое сечение - это x²-x-1=0


  1. friend001002
    18.02.2025 08:53

    Это они изобретали велосипед, чтобы на мобилках работало быстро? Раз дали пользователю возможность вводить подобные выражения, то почему их не считать давно написанными и протестированными библиотеками символьных вычислений?


  1. grigorym
    18.02.2025 08:53

    2*pi + 3*sqrt(2), допустим, представляются в таком виде. Но я не догнал, как они смогут представить pi^pi, если там везде только произведение "хорошего" числа на "плохое". Что-то я, видимо, не понимаю.


    1. Mingun
      18.02.2025 08:53

      Вероятно, экспонента от логарифма или наоборот


  1. zzzzzzzzzzzz
    18.02.2025 08:53

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