Как стать автором
Обновить

Величайшая история разработки приложения-калькулятора: как Google создал почти идеальный инструмент

Уровень сложностиПростой
Время на прочтение6 мин
Количество просмотров29K
Всего голосов 84: ↑77 и ↓7+87
Комментарии99

Комментарии 99

(10^100) + 1 − (10^100) равно 0, а не 1

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

Так автор пишет не про то, что это так, а про калькулятор айфона, который даёт такой ответ. Или, как минимум, про калькулятор айфона на тот момент времени. У кого айфон, проверьте, сейчас это так или нет?

Блин, давайте я вам единицу хоть в сотую степень возведу, хоть в 100500-ю. В уме, безо всяких калькуляторов.

Дак не в степенях единицы суть (даже не в степени десятки)

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

GNU Octave 6.4, к слову, в численном решении тоже выдаёт 0

А вы присмотритесь, там возводят именно единицу. И в двух других комментариях делают 10 XOR 100.

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

Что такое плавучка - я знаю. И что такое BigInt, тоже какое-то представление имею (даже вживую использовал. На 8-битном микроконтроллере были нужны 6-байтные числа. Потом выкинули эти велосипеды, взяли банальный uint64_t. Стало хотя бы читаемо).

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

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

Я вам больше скажу — на каждом инженерном калькуляторе есть кнопка [хʸ], но вместе с ней также есть кнопки [10ˣ], [x² ] и др. На первый взгляд кажется, что: если есть универсальная кнопка [хʸ] и используя ее можно ввести «любое число в любой степени (в том числе и в дробной)» — значит другие кнопки присутствуют для удобства ввода. А вот и нет! Дело в том, что математические операции, закрепленные за этими кнопками, осуществляются по разным алгоритмам. На маленьких числах это может быть не заметным, но на больших видно сразу.

Впервые эту особенность обнаружил на СССР-овских калькуляторах МК-61 и МК-52, чему был несказанно удивлен. И только уже позже, в институте, преподаватель объяснил, что операции на кнопке [хʸ] выполняются через функцию и поэтому получается некоторая погрешность, в отличие от других кнопок — на них точнее.

Почему 1? В примере 10.

А13 MIUI 14 с com.miui.calculator версии 12.3.77 выдаёт вот это (при добавлении скобок в выражение результат всё тот же):

А иногда и так

Если ничего не путаю, то результат должен был получиться 9.0E+99

Это просто рука-лицо. Я смотрю, что люди считают и видно, что они вообще не поняли статью. То зачем-то единицу возводят в сотую степень, то путают сложение с вычитанием. Грустно...

Так автор ж пишет (ну или переводчик переводит так)

Взгляните на калькулятор iOS. Что-нибудь заметили? Он показывает неверный результат. (10^100) + 1 − (10^100) равно 0, а не 1.

И ниже на картинке 1 как раз, как будто это и есть неверный результат

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

Автор уже поменял картинку

Айфоновский просто для сравнения упомянут.

Явно ж не 'просто упомянут для сравнения', раз 'Взгляните'

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

Вместо айфона можете то же самое ввести в консоли браузера, тоже получится 0.

А при чем здесь вы, как раз речь о том что в андроиде калькулятор нормально сделали. Это не значит что qalc должен тоже считать неверно. Хотя вон даже гугл выдает неверный ответ

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

и Яндекс

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

> речь о том что в андроиде калькулятор нормально сделали

Это конечно достижение :) :) :)

Нобелевку ему!

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

у вас калькулятором послужила нейросетка яндекса

а у меня некий "обычный" калькулятор в поиске

у вас калькулятором послужила нейросетка яндекса

Знаю. Только это было не мое решения выбрать инструмент для расчета, а Яндекса. Я просто ввел в поисковую строку математическое выражение и нажал Enter.

В смысле, я имел ввиду, что у вас Яндекс и у меня Яндекс, а считает по разному.

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

JS и C в этом плане удивительные языки, в них можно даже так писать:

x = 5;
x ^= 2;

/s /s /s

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

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

В консоли используется js, возведение в степень там **. А ^ это битовый xor.:)

В js это выглядит так:

10**100 + 1 - 10**100

Не обязательно даже брать настолько большие числа, достаточно таких:

1e+20 + 1 - 1e+20

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

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

Так вот условные 10^100 в такое число помещаются, но там не то что 1, там даже 10 уже за пределами точности такого числа. И такая операция как плюс (или там минус), просто ни на что не повлияет.

Выходит что исходное число не поменяется, а два представления 10^100 для компьютера выглядят одинаково (к сожалению, даже это не всегда так). Но отсюда и получается 0.

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

Не в превью, а в формулировках.

Он показывает неверный результат. (10^100) + 1 − (10^100) равно 0, а не 1.

Это два разных предложения. В первом заявляется, что "он" (калькулятор) показывает неверный результат, второе утверждает, что значение выражения равняется нулю.
Они вместе не утверждают, что калькулятор на ios выдаёт для выражение значение 0, когда должен бы выдавать 1. Об этом приходится догадываться.

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

В имеющейся конструкции оно не описывает вычисление на калькуляторе айфона ¯_(ツ)_/¯

Он показывает неверный результат: (10^100) + 1 − (10^100) [у него] равно 0, а не 1, [как должно быть].

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

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

Который будет складывать и умножать в столбик по одной цифре, как это делают люди

Я такое чисто по приколу делал еще лет 30 назад) По сути работаем с цифрами как с символами, в роли арифметики - простой поиск по таблице. То есть вообще не используя арифметику машины и языка программирования.

Но эта штука хоть и позволяла работать с числами длиной миллионы знаков, была до жути медленной, ОЗУ жрало как не в себя, собственно куда такое можно применить, я и не нашел. Тоже бесило, что даже компуктер с его мегабайтами памяти не может мне посчитать дофигазначное число (этот факт бесил еще со времен первых калькуляторов, да!).

В Ruby есть тип BigDecimal, который псевдостроковой и работает именно «по школьной математике» (умножение/деление «в столбик» и т. п.)

Symbolic computation. Реализовано много где, например, есть совершенно чудесная питонячья библиотека SymPy.

если бы калькулятор показал 0 для e^(-10000), это было бы неправильно. Это не 0. Должно быть 0,00000... и вы можете прокручивать, пока не увидите первую цифру.

Можно же выдать просто 1.135483865E−4343. Разве это так трудно?

Для Андроида смогли написать калькулятор. Шок-контент без смс...

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

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

Оригинал с твиттера, на этом сайте выше просто развернутый тред. Там же была опечатка с этой формулировкой про 0 и 1, где все подумали что 0 это правильно – на что автор сказал, что он просто опечатался, а в тредах менять уже нельзя нормально корневой твит даже с синей галкой. Но переводчик, не включив логику, взял и перевел с этой же опечаткой как есть, что вызвало те же самые вопросы, что и в твиттере.

Это не спортивно. sympy даже во встроенные библиотеки не входит.
PS

print(sympify('10**100+1-10**100'))
1
print(sympify('10**100+1-0.1*10**101'))
0

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

print(type(math.pi))
print(type(math.sin(math.pi)))
print('{0:.70f}'.format(0.1 + 0.2))
# <class 'float'>
# <class 'float'>
# 0.3000000000000000444089209850062616169452667236328125000000000000000000

PS: надо послушать тех, кто умеет ей пользоваться. Вижу, что фиксится через
, rational=True

Логика в том, что десятичная дробь триггерит переход к неточной плавающей запятой и эта же логика в MATLAB'е и Wolfram Alpha.

from sympy import *
print(sympify('10^100 + 1  - 0.1*10^101')) # 0
print(sympify('10^100 + 1  - 1/10*10^101')) # 1
print(sympify('10^100 + 1  - 0.1*10^101', evaluate=False).simplify()) # 0
print(sympify('10^100 + 1  - 0.1*10^101', rational=True)) # 1

# MATLAB:
# sym('10^100 + 1 - 0.1*10^101')      # 0.0
# sym('10^100 + 1 - 1/10*10^101')     # 1
# vpa('10^100 + 1 - 0.1*10^101', 100) # 1.0

# Wolfram Alpha https://www.wolframalpha.com/input?i=1+-+1%2F10*10%5E100
# 1 - 0.1*10^101 = -1*10^100
# 1 - 1/10*10^101 = 1 - 1/(10×10^100)

Мелкая ошибка: Wolfram Alpha распарсил 10*10^101 как одно число в научной нотации и целиком поместил в знаменатель, но слова про логику верны: у него 1 - (1/10)*10^101 = -99999....

С проблемой десятичных дробей, если они всё же нужны, борются "рационализацией" float'ов доступными средствами (sympy: [1][2][3], MATLAB: предлагают страдать).

Для меня тут самое удивительное не то, что Ханс залез в такие дебри, а то что человеку такого уровня дали писать калькулятор. Разве что сам сказал за пивом Брину с Пейджем "вы ничего не понимаете, только я сделаю правильно".

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

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

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

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

Не, это неинтересно — это ведь не сборщик мусора писал.

По тексту получается, что писал сборщик мусора: «Google нанял Ханса-Дж. Боэма, известного как „сборщик мусора Боэма“.» В оригинале речь идёт о том, что «Google hired Hans-J. Boehm, of the „Boehm garbage collector“ fame». То есть речь идёт про то, что человек заработал имя на сборщике мусора своего авторства.

Ну и дальше там постоянно признаки наспех выполненного машинного (или просто без любви к тексту и читателю) перевода:

  • Отсутствие проверки общеупотребительных терминов. В русской литературе его обычно называют «алгоритм Кэхана», но в англоязычной он известен как «Kahan summation algorithm». При дословном переводе получится как в тексте выше — «алгоритм суммирования Кэхана».

  • Было бы неплохо сделать прим. пер. и привести реальное имя Роберта Картрайта, а не просто его никнейм «Корки», как в оригинале. В любом случае, научные публикации ищутся по официальному имени.

  • Наконец, текст попросту переведён не до конца. Автор бросил переводить его на одном из твитов, сунул туда ссылку на свой канал в «Телеграме» и опубликовал перевод.

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

Угу, я тоже только попкорн достал... Резануло еще намного, что вместо рациональных и иррациональных чисел всякие другие слова )

Эти математические дебри, конечно, хорошо... Но лично мне куда больше бы пригодилась фича сохранения/извлечения числа из памяти, которая была в любом неплохом железном калькуляторе еще в 90-х, но до которой за 20+ лет существования Андроид так никто и не додумался >_< Или, например, 1/X - чего уж проще.

Или, например, 1/X

Так есть же.
Вот, например, я кидал скриншот куркулятора от сяоми (емнип, можно ставить на любой смарт, лишь бы ведроид был подходящей версии):
https://habr.com/ru/articles/883028/comments/#comment_27933764

Хорошо, это есть, а как насчет М+/-/R? Простейшие же, но очень нужные штуки. 1/Х еще можно заменить на ^-1, ладно, это суровый закон выживания - если не шаришь в алгебре за 7 класс, нечего тебе делать в калькуляторе (сарказм; ни за что не поверю, что факториал настолько часто востребован в штатном калькуле на телефоне), но уж работу с ячейкой памяти почему никто не делает?

Какой бы крутой калькулятор не казался, а вот кнопок М+. М- и RM ну очень не хватает. В дешёвых китайских калькуляторах 1991 года уже были эти кнопки

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

Может и в других калькуляторах стоит поискать?

И история есть, и копипаста работает.

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

Потом поставить другое выражение, приплюсовать его к предыдущему (М+)

Потом третье и т.д.

Например, площади всех комнат.

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

HiPER Scientific Calculator имеет эти кноки (только результатом вычисления проблемного выражения у него тоже является ноль).

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации