Математика с плавающей точкой нарушена?

Если по «файлу изображения» вы имеете в виду те файлы растрового изображения, которые распознаются графической системой VCL, а «перед открытием» вы имеете в виду «прежде чем пользователь может заметить, что файл открыт», то вы можете сделать это очень легко:

var
  pict: TPicture;
begin
  with TOpenDialog.Create(nil) do
    try
      if Execute then
      begin
        pict := TPicture.Create;          
        try
          pict.LoadFromFile(FileName);
          Caption := Format('%d×%d', [pict.Width, pict.Height])
        finally
          pict.Free;
        end;
      end;
    finally
      Free;
    end;

Конечно, файл открыт , и для этого требуется большая память, если изображение большое. Однако, если вам нужно получить metatada (например, размеры) без загрузки файла, я считаю, что вам нужно более «сложное» решение.

2723
задан NathanOliver 29 April 2019 в 14:53
поделиться

6 ответов

Двоичный файл плавающая точка математика похож на это. На большинстве языков программирования это основано стандарт IEEE 754 . JavaScript использует 64-разрядное представление с плавающей точкой, которое совпадает с Java double. Затруднение проблемы - то, что числа представлены в этом формате в целом времена числа питание два; рациональные числа (такой как 0.1, который является 1/10), чей знаменатель не является питанием два, не могут быть точно представлены.

Для 0.1 в стандарте binary64 формат, представление может быть записано точно как [1 138]

  • 0.1000000000000000055511151231257827021181583404541015625 в десятичном числе, или
  • 0x1.999999999999ap-4 в [1 127] нотация .

C99 hexfloat Напротив, рациональное число 0.1, которое является 1/10, может быть записано точно как [1 139]

  • 0.1 в десятичном числе, или
  • 0x1.99999999999999...p-4 в аналоге нотации C99 hexfloat, где эти ... представляет бесконечную последовательность 9's.

константы 0.2 и 0.3 в Вашей программе также будут приближениями к своим истинным значениям. Это происходит, что самое близкое double к [1 115] больше, чем рациональное число 0.2, но что самое близкое double к [1 118] меньше, чем рациональное число 0.3. Сумма [1 120] и 0.2 завершает то, чтобы быть больше, чем рациональное число 0.3 и следовательно не соглашающийся с константой в Вашем коде.

А довольно всесторонняя обработка арифметических проблем с плавающей точкой , Что Каждый Программист Должен Знать Об Арифметике С плавающей точкой . Для более легкого к обзору объяснения см. floating-point-gui.de .

Примечание Стороны: Все позиционные (основные-N) системы счисления совместно используют эту проблему с точностью

Простое десятичное число (базируйтесь 10), числа имеют те же проблемы, который является, почему числа как 1/3 заканчиваются как 0,333333333...

Вы только что наткнулись на номер (3/10), который, оказывается, легко представить с десятичной системой счисления, но не соответствует двоичной системе счисления. Это идет обоими путями (до некоторого маленького градуса) также: 1/16 является ужасным числом в десятичном числе (0.0625), но в двоичном файле это выглядит столь же аккуратным, как 10,000-е делает в десятичном числе (0.0001) ** - если бы мы имели привычку использовать основу 2 системы счисления в наших повседневных жизнях, то Вы даже посмотрели бы на то число и инстинктивно поняли бы, что могли прибыть туда путем сокращения вдвое чего-то, сокращения вдвое его снова, и снова и снова.

**, Конечно, это не точно, как числа с плавающей запятой хранятся в памяти (они используют форму экспоненциального представления). Однако это действительно иллюстрирует тезис, что двоичные ошибки точности с плавающей точкой имеют тенденцию неожиданно возникать, потому что числа "реального мира", с которыми мы обычно интересуемся работой, так часто полномочия десять - но только потому, что мы используем ежедневную десятичную систему счисления. Это также, почему мы скажем вещи как 71% вместо "5 из каждых 7" (71% приближение, так как 5/7 не может быть представлен точно ни с каким десятичным числом).

Так нет: двоичные числа с плавающей точкой не повреждаются, они просто, оказывается, так же несовершенны как любая основная-N система счисления:)

Примечание Стороны Стороны: Работая с Плаваниями в Программировании

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

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

Делают не , делают if (float1 == float2) { ... }

, Вместо этого делают if (Math.Abs(float1 - float2) < myToleranceValue) { ... }.

myToleranceValue должен быть выбран для Вашего конкретного приложения - и это будет иметь много, чтобы сделать с тем, сколько "пространства для маневра" Вы готовы позволить, и что наибольшее число Вы собираетесь быть сравнением, может быть (из-за потери проблем точности). Остерегайтесь "дважды. Эпсилон" константы стиля на Вашем предпочтительном языке (Число. ЭПСИЛОН в JavaScript). Это не , чтобы использоваться в качестве значений допуска.

2062
ответ дан 20 revs, 15 users 33% 30 April 2019 в 00:53
поделиться

Когда Вы преобразовываете.1 или 1/10 для базирования 2 (двоичный файл), Вы получаете повторяющийся шаблон после десятичной точки, точно так же, как попытка представить 1/3 в основе 10. Значение не точно, и поэтому Вы не можете сделать точной математики с ним с помощью нормальных методов с плавающей точкой.

429
ответ дан Joel Coehoorn 30 April 2019 в 00:53
поделиться
  • 1
    Я просто расширил свой ответ, чтобы показать, как зарегистрировать все Ваши контроллеры, включая все методы с одной строкой. – Hexodus 4 April 2013 в 08:01

Погрешность округления с плавающей точкой. От , Что Каждый Программист Должен Знать Об Арифметике С плавающей точкой :

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

46
ответ дан Nae 30 April 2019 в 00:53
поделиться
  • 1
    Это - очень изящное решение. @Tareck117, it' s возможный, что это могло влиять на производительность, однако, не так, что она должна будет быть сфокусирована на немедленно (хотя это - низко висящий плод). – Tim Groeneveld 3 May 2014 в 15:40

Погрешности округления с плавающей точкой. 0.1 не может быть представлен так же точно в основе 2 как в основе 10 должных к недостающему простому множителю 5. Так же, как 1/3 берет бесконечное число цифр для представления в десятичном числе, но "0.1" в основе 3, 0.1 берет бесконечное число цифр в основе 2, где это не делает в основе 10. И компьютеры не имеют бесконечного объема памяти.

207
ответ дан Devin Jeanpierre 30 April 2019 в 00:53
поделиться
  • 1
    Право.. но вопрос состоит в том, что сделать, когда файл Routes.php становится большим от регистрации такого количества контроллеров. Также для простых маршрутов и материала, it' s не всегда логичный для создания контроллера для них и это сделает размер файла маршрутов больше также. Лучшая практика должна создать несколько файлов маршрутов и include их в routes.php? – Chris G. 26 February 2013 в 13:04

Я просто видел эту интересную проблему вокруг плавающих точек:

Рассматривают следующие результаты:

error = (2**53+1) - int(float(2**53+1))
>>> (2**53+1) - int(float(2**53+1))
1

Мы можем ясно видеть точку останова, когда 2**53+1 - все хорошо работает до 2**53.

>>> (2**53) - int(float(2**53))
0

Enter image description here

Это происходит из-за двоичного файла двойной точности: двоичный файл двойной точности IEEE 754 формат с плавающей точкой: binary64

От страницы Wikipedia для Двойная точность формат с плавающей точкой:

двоичный файл Двойной точности, с плавающей точкой, является наиболее часто используемым форматом на ПК, из-за шире передвигаются на плавающую точку с одинарной точностью, несмотря на ее производительность и стоимость пропускной способности. Как с форматом с плавающей точкой с одинарной точностью, это испытывает недостаток в точности на целых числах по сравнению с целочисленным форматом того же размера. Это обычно известно просто как дважды. Стандарт IEEE 754 указывает binary64 как наличие:

  • Знаковый бит: 1 бит
  • Экспонента: 11 битов
  • Значительная точность: 53 бита (52 явно сохраненный)

Enter image description here

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

Enter image description here

или

Enter image description here

Благодаря @a_guest для указания на это мне.

1
ответ дан 22 November 2019 в 19:51
поделиться

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

Например:

var result = 1.0 + 2.0;     // result === 3.0 returns true

... вместо:

var result = 0.1 + 0.2;     // result === 0.3 returns false

Выражение 0.1 + 0.2 === 0.3 возвращает false в JavaScript, но, к счастью, целочисленная арифметика с плавающей точкой является точной, поэтому ошибки десятичного представления можно избежать путем масштабирования.

В качестве практического примера, чтобы избежать проблем с плавающей точкой, когда точность имеет первостепенное значение, рекомендуется1 обращаться с деньгами как с целым числом, представляющим количество центов: 2550 центов вместо 25.50 долларов.


1 Дуглас Крокфорд: JavaScript: Хорошие части: Приложение A - Ужасные части (страница 105).

117
ответ дан 22 November 2019 в 19:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: