Добрый день! Заметил необычное поведение Excel при вводе цифр в диапазоне 33000-65000 со значениями "0,098" или "0,848" после запятой. При вводе они превращаются в 33000,0979999999 и 33000,8479999999. Проблема возникает на двух компьютерах в двух независимых фирмах. У меня стоит Excel 2013. На данный момент вышел из этой ситуации, применив текстовый формат к ячейкам. Есть идеи, отчего возникает такая ошибка округления и как ее устранить?
Эта тема неоднократно поднималась и на этом форуме - поищите в архиве, если интересно: Если Вам требуются результаты с точностью до двух (или подставьте конкретное число) знаков после запятой, то используйте функции ОКРУГЛ() и пр. Если же Вас смущают исключительно некорректные представления числе на экране/на бумаге, то можно обойтись просто корректировкой форматов
Интересный документ, почитаю. Сам программирую и давно отказался от форматов single и double в выражениях, где потери копеек недопустимы.
Цитата
sokol92 написал: Наберите в поиске по сайту "Приближенные вычисления".
Про вычисления с ошибкой я давно знаю. Знаю также что в память числа с плавающей точкой изначально записываются с погрешностью. Но тут, вроде как, введено вручную, и такой фокус)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
IKor написал: Если же Вас смущают исключительно некорректные представления числе на экране/на бумаге, то можно обойтись просто корректировкой форматов
Да, я просто перевел ячейки в текстовый формат и все ок. Работаю с Excel уже лет 15 и такой проблемы при вводе не встречал, только при вычислениях. На экране и печати все ок, всех устраивает, видно только в редакторе формул. Старому другу директор стал задавать вопросы, типа "Зачем ты всякую ерунду в ячейках пишешь? Откуда эти цифры?" и т.д.. Он обратился ко мне и я неплохо так озадачился =) Подумал, вдруг это настройками правится, но не нашел подходящих, решил здесь спросить.
Jack Famous написал: Спасибо за баг - при вводе такого не видел ещё
Здесь нет никакого бага. Расхождение в 16-й значащей цифре не является багом.
Вы хотите увидеть в ячейке 33000,098. Это число не может быть точно представлено в формате double. Вместо этого Вам Excel показывает 33000,0979999999 Разница между указанными двумя значениями вполне соответствует точности представления чисел в формате double. Если хотите видеть числа в "человеческом" виде, используйте "числовой" формат.
sokol92, приветствую, Владимр! Мы уже с вами обсуждали этот момент и сошлись на том, что вы судите с технико-юридической точки зрения, согласно которой как раз "расхождение в 16-й значащей цифре не является багом", а я сужу с пользовательско-практической точки зрения, которая подсказывает, что, если я ввожу число 33000,098, то именно его я хочу увидеть в ячейке, а не "33000,0979999999"
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Что при вводе, что при вычислениях Стандарт IEEE 754 един.
Цитата
FearDog написал: Сам программирую и давно отказался от форматов single и double в выражениях, где потери копеек недопустимы.
есть пример вычислений, где 15 разрядов после запятой не хватает для правильного расчета копеек (2х разрядов)? т.е. погрешность при вычислении в 13 разрядов. Даже если вы считаете милиарды, 5-6 знаков после запятой (10-9 на целое число) вполне достаточно для расчета копеек (или я заблуждаюсь)?
Цитата
Jack Famous написал: что, если я ввожу число 33000,098, то именно его я хочу увидеть в ячейке, а не "33000,0979999999"
Привет, поставь формат ячейки с 2 знаками после запятой и будет тебе желаемое )
Тут проблема в том, что "баг" - это недокументированная ошибка программы, которую разработчики пропустили. А тут указанные погрешности в числах с плавающей запятой прекрасно и подробно документированы... Так что с точки зрения пользователя ничего не остается как смириться, т.к. фиг чего с этим сделаешь.
Цитата
Jack Famous написал: при вводе такого не видел ещё
это тянется еще с 2003 Excel - помню подобную проблему еще там. Таких чисел вообще много. Например вот 37869,598 или вот 57719,473
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
В период гиперинфляции в РФ при расчете балансовой (первоначальной) стоимости основных средств на крупных предприятиях формат double давал погрешность в копейках. Правда, можно было вести учет стоимости ОС в целых рублях.
bedvit: Что при вводе, что при вычислениях Стандарт IEEE 754 един
привет)) ну как сказать: смотри, я же могу ввести в ячейку число "0,1" и оно будет выглядеть, как "0,1". Но, если я напишу =10,8-10,7, то результат будет с хвостом. То есть, отобразить "0,1" Excel может, но в данном случае, при вычислении получается не свовсем он. С числами же типа "33000,098" другая история - Excel не может даже просто отобразить их (не как результат вычисления)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
sokol92 написал: формат double давал погрешность в копейках.
Владимир, и каким форматом пользовались? Decimal?
Цитата
Jack Famous написал: число "0,1" и оно будет выглядеть, как "0,1". Но, если я напишу =10,8-10,7, то результат будет с хвостом. То есть, отобразить "0,1" Excel может, но в данном случае, при вычислении получается не свовсем он.С числами же типа "33000,098" другая история
Алексей, это все одна и та же история. Просто нужно внимательно прочитать формат Стандарт IEEE и понять, почему так происходит. Комп работает с двоичным представлением данных/числа/чего угодно. Поэтому некоторые десятичные значения привычные для нас, в двоичном представлении это бесконечная дробь. С бесконечностями работать не умеет, да и памяти столько нет, и т.к.в double всего 64 бита имеем погрешность расчета. Так же как и например 1/3=0,333333(3) в десятичной системе, вы же округляете при расчете?
Цитата
Jack Famous написал: я не знаю этого "волшебства"?)))
это не волшебство, а решение твоего вопроса (чем не устраивает?)
Дело как раз в том, что задача программиста спрятать эти "документированные" проблемы подальше от пользовательских глаз))) Почему Excel это не учли, непонятно. с 0,1 же все ок =)
Цитата
Jack Famous написал: смотри, я же могу ввести в ячейку число "0,1" и оно будет выглядеть, как "0,1". Но, если я напишу =10,8-10,7, то результат будет с хвостом. То есть, отобразить "0,1" Excel может, но в данном случае, при вычислении получается не совсем он. С числами же типа "33000,098" другая история - Excel не может даже просто отобразить их (не как результат вычисления)
Было много ситуаций в написании и макросов, и программ, когда я сначала пытался доказать, что что-либо невозможно, а потом брал и делал, учитывая все подводные камни =)
Цитата
FearDog написал: "Зачем ты всякую ерунду в ячейках пишешь? Откуда эти цифры?" и т.д.
Порой сложно Директору объяснить, "зачем и почему", ему нужно "чтобы красиво было" =)
Или отправляешь такой смету контрагенту, а он: "Чего-то вы тут мухлюете, округляете как-то странно, обмануть нас хотите!?!?"
Да и разговоры про потерю точности, бла бла бла... - все фигня. Можно спокойно написать класс, который будет корректно выполнять операции с точностью свыше 100 знаков после запятой (конечно с небольшими потерями производительности, но на дворе не 89 год). Тут MS видимо поленились, при том что прослеживается определенная зависимость=)
Oracle и другие "большие" базы имеют для чисел собственный формат (тип NUMBER Oracle обеспечивает 33 "точных" десятичных цифры). Если кроме double иных поддерживаемых форматов в базах не было - считали в целых рублях. Кроме того, для минимизации ошибок округления при суммировании больших массивов данных умножали предварительно суммы в копейках на 100 и округляли до целого; при записи результата в базы данных - делили на 100. Голь на выдумки...
Кстати, в VBA есть тип Currency, который не дает ошибок округления при суммировании чисел, имеющих не более 4 знаков после десятичной запятой.
Дробные числа даже с одним десятичным знаком (отличном от 5) имеют погрешность представления в формате double (в отличие от целых, имеющих не более 15 цифр).
sokol92, Владимир, Excel не согласен с тобой =10,8-10,7 (Excel) = 0,100000000000001 =(10,8*10-10,7*10)/10 (Excel) = 0,100000000000000 Или это не корректный пример?
Если Директор достаточно грамотен для того, чтобы заглянуть в редактор формул, то вероятно ему можно на пальцах объяснить причины и следствия этой особенности MS Excel Тем более, что его всегда можно попросить лично внести в ячейку число 33000,098
bedvit написал: Владимир, Excel не согласен с тобой
Другой алгоритм: 1. 10,8 * 100=1080 (и округляем до целого). Аналогично 10,7 -> 1070. 2. 1080-1070=10. 3. Результат 10 / 100 (представим в double с минимально возможной погрешностью).
Сейчас напишу UDF - функцию, аналогичную Sum, которая без погрешности суммирует дробные числа, содержащие до 4 знаков после запятой.
Код
Option Explicit
Function ExactSum(ParamArray args()) As Double
Dim result As Currency, arg, v
On Error Resume Next
For Each arg In args
If IsObject(arg) Then
arg = arg.Value
End If
If IsArray(arg) Then
For Each v In arg
result = result + CCur(v)
Next v
Else
result = result + CCur(arg)
End If
Next arg
On Error GoTo 0
ExactSum = result
End Function
формат-то все равно double. Вопрос в дробной части, в ней вся погрешность этого формата. Decimal без этой проблемы, но им пользоваться можно с некоторыми особенностями (VBA).
После умножения суммы в копейках на 100 и округления до целого погрешности нет. В функции из #23 используется тот же метод (с учетом специфики внутреннего представления типа Currency).
bedvit: это не волшебство, а решение твоего вопроса (чем не устраивает?)
это не решение, а костыль. Да, разумеется, я бы так и сделал для красивой картинки в отчёте, но мне не нравится, что мелкомягкие просто "задокументировали" собственное бессилие и типа всё ок
Цитата
FearDog: Можно спокойно написать класс, который будет корректно выполнять операции с точностью свыше 100 знаков после запятой
вот именно. И хочется, чтобы в таком глобальном продукте этот вопрос был решён, а то стыдоба ей-богу
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
FearDog написал: Можно спокойно написать класс, который будет корректно выполнять операции с точностью свыше 100 знаков после запятой
да давно уже написан. Вот и я ранее приобщался (любое количество символов насколько хватит оперативки, для Excel - сколько влезет в ячейку 32 тыс.) Но кому нужна такая точность?
Это не костыль, это особенность работы чисел с плавающей точкой. а какие есть альтернативы? (кроме форматов с копейками, которые считаются через целые, примерно так же, как выше Владимир оформил)
в вычислениях встраивать в движок округление до 14-15 знаков, если по-другому стандарт не позволяет или умножение на 10^ максимальное количество знаков после запятой у участвующих членов, расчёт с целыми и последующее деление на тот же коэффициент, как Владимир выше показывал. При вводе: я ХЗ, как исправить то, что Excel даже не может корректно отобразить ручной ввод
Основной посыл очень здорово сформулировал Дима:
Хочется верить, что хоть когда-нибудь описанную особенность стандарта IEEE754 Microsoft сможет победить или хотя бы сделать заплатку, которая будет производить простые вычисления не хуже 50-рублевого калькулятора
К этому теперь можно добавить "и отображать числа так, как они были введены"
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Вариант с округлением звучит логично, в моей библе так и реализовано, считаю на один знак больше и округляю под заданную точность (вернее так считает MPIR/GMP). Почему Excel не округляет на 15м знаке, не осведомлен, возможно дело в производительности, наличия для этого функций или формата ячеек.
Цитата
Jack Famous написал: IEEE754 Microsoft сможет победить
для меня не ясен этот момент, стандарт международный, реализован и на аппаратном уровне (в т.ч. в вашем ЦП). Мягкотелые на него не влияют. Возможно вопрос в округлении в ячейках Excel, тогда да, согласен, это было бы логично.
Excel 2010 При вводе 33000,098 в ячейке так и отображается (при разрядности 3-9 знаков после запятой), в строке формул отображается 33000,0979999999. При суммировании двух ячеек со значениями 33000,098 получаем 66000,196, так что проблемы нет, смущает только отображение в строке формул.