Сценаристы должны рассмотреть ошибку округления?

Возможно обработать осведомленное о локали "Да / Никакой выбор" в оболочке POSIX; при помощи записей LC_MESSAGES категория локали, ведьма обеспечивает готовые шаблоны RegEx для соответствия входу и строкам для локализованного Да №

#!/usr/bin/env sh

# Getting LC_MESSAGES values into variales
IFS='
' set -- $(locale LC_MESSAGES)

yesexpr="$1"
noexpr="$2"
yesstr="$3"
nostr="$4"
messages_codeset="$5" # unused here, but kept as documentation

# Display Yes / No ? prompt into locale
echo "$yesstr / $nostr ?"

# Read answer
read -r yn

# Test answer
case "$yn" in
# match only work with the character class from the expression
  ${yesexpr##^}) echo "answer $yesstr" ;;
  ${noexpr##^}) echo "answer $nostr" ;;
esac
5
задан brian d foy 31 August 2009 в 22:02
поделиться

9 ответов

Я бы не согласился с Лутцем ... Хотя упомянутые вами ошибки округления существуют в Python / Perl / Ruby, они не имеют абсолютно отношения к языкам. реализуется на C. Проблема идет глубже.

Числа с плавающей запятой, как и все данные, на современных компьютерах представлены в двоичном формате. Так же, как есть числа с периодическим десятичным представлением (например, 1/3 = 0,333333 ...), есть также числа с периодическим двоичным представлением (например, 1/10 = 0,0001100110011 ...). Поскольку эти числа не могут быть точно представлены в (ограниченном объеме) памяти компьютера, любые вычисления, связанные с ними, приведут к ошибке.

Это можно обойти, используя высокоточные математические библиотеки, которые представляют числа либо как два числа. дроби (например, «числитель = 1,

7
ответ дан 18 December 2019 в 05:44
поделиться

В Python есть несколько типов нецелых чисел:

x = 1 / 2

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

Однако, существует также дробный тип :

from fractions import Fraction

x = Fraction(1, 2)

, который имеет точную арифметику с рациональными числами.

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

from decimal import Decimal

x = Decimal('0.5')

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

Пока компьютеры глупы, мы ' вам, вероятно, понадобится столько разных типов. По крайней мере, в соответствии с принципами Pythonic, Python требует, чтобы вы сделали явный выбор того, что вы хотите от своих чисел.

Более того, это большое недоразумение, что точная арифметика не приводит к проблемам с округление. Каждый раз, когда вы округляете точное значение, чтобы сделать с ним что-то полезное для пользователя - например, распечатать его для пользователя или добавить столько долларов на банковский счет пользователя - вы сталкиваетесь со «странным поведением» округления. Это свойственно нецелочисленной арифметике.

Каждый раз, когда вы округляете точное значение, чтобы сделать с ним что-то полезное для пользователя - например, распечатайте его для пользователя или добавьте столько долларов на банковский счет пользователя - вы сталкиваетесь со «странным поведением» округления. Это свойственно нецелочисленной арифметике.

Каждый раз, когда вы округляете точное значение, чтобы сделать с ним что-то полезное для пользователя - например, распечатать его для пользователя или добавить столько долларов на банковский счет пользователя - вы сталкиваетесь со «странным поведением» округления. Это свойственно нецелочисленной арифметике.

6
ответ дан 18 December 2019 в 05:44
поделиться

Это зависит от обстоятельств. double ведут себя одинаково везде, поэтому, если вы выполняете математические вычисления с двойными числами, у вас будет такая же проблема с любым языком. Если вы используете собственный тип произвольной точности, то нет, это не проблема. Рассмотрим:

use Math::BigFloat;
my $big   = Math::BigFloat->new("1_000_000_000_000_000_000_000");
my $small = Math::BigFloat->new("0.000000000000000000000000001"); 
print $big + $small;

(Или, если вы действительно хотите скрыть, что происходит:

use bignum;
print 1_000_000_000_000_000_000_000 + 0.000000000000000000000000001

)

Как и ожидалось, это дает:

1000000000000000000000.000000000000000000000000001

Также, как и ожидалось, это не выполняется в одной инструкции ЦП.

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

use Math::BigFloat;
my $big   = Math::BigFloat->new("1_000_000_000_000_000_000_000");
my $small = Math::BigFloat->new("0.000000000000000000000000001"); 
print $big + $small;

(Или, если вы действительно хотите скрыть, что происходит:

use bignum;
print 1_000_000_000_000_000_000_000 + 0.000000000000000000000000001

)

Как и ожидалось, это дает:

1000000000000000000000.000000000000000000000000001

Также, как и ожидалось, это не выполняется в одной инструкции ЦП.

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

use Math::BigFloat;
my $big   = Math::BigFloat->new("1_000_000_000_000_000_000_000");
my $small = Math::BigFloat->new("0.000000000000000000000000001"); 
print $big + $small;

(Или, если вы действительно хотите скрыть, что происходит:

use bignum;
print 1_000_000_000_000_000_000_000 + 0.000000000000000000000000001

)

Как и ожидалось, это дает:

1000000000000000000000.000000000000000000000000001

Также, как и ожидалось, это не выполняется в одной инструкции ЦП.

10
ответ дан 18 December 2019 в 05:44
поделиться

Поскольку реализован базовый интерпретатор как CPython, так и Perl в C они ведут себя как программа C.

Для Python существуют SciPY и NumPy для научных вычислений.

2
ответ дан 18 December 2019 в 05:44
поделиться

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

Например, если я пишу весь свой код на ассемблере 8051, но реализовал изящную библиотеку рациональных чисел, тогда округление не проблема. 1/3 равняется только 1/3.

Однако, если я использую последний шикарный динамический язык, и в нем используются числа с плавающей запятой IEE754, тогда применяются все ограничения IEEE754.

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

Обновление:

PDL - популярная библиотека для выполнения научных вычислений на Perl.

4
ответ дан 18 December 2019 в 05:44
поделиться

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

Доказательство: Допустим, вы хотите отслеживать движение молекулы у границы Вселенной. Размер Вселенной составляет около 93 миллиардов световых лет (насколько нам известно). Молекула довольно крошечная, поэтому вам понадобится как минимум нанометровая точность (10 ^ -6). Это 50 порядков.

По какой-то причине вам нужно повернуть эту молекулу. Это включает операции sin () и cos () и умножение. Умножение не является проблемой, поскольку количество действительных цифр - это просто сумма длин обоих операндов. Но как насчет sin () ?

Вы должны создать уравнение ошибки, чтобы быть уверенным, что вы сохраняете достаточное количество цифр, чтобы окончательный результат имел известную максимальную ошибку. Я не знаю ни одной «простой» числовой библиотеки, которая могла бы выполнять эту операцию автоматически (скажем, как часть вызова sin () ). Здесь вам понадобится Matlab или что-то подобное.

0
ответ дан 18 December 2019 в 05:44
поделиться

Вы можете выполнять вычисления с множественной точностью с помощью Python с помощью внешних модулей. В разделе Multi Precision Math на официальном веб-сайте перечислены многие из них.

1
ответ дан 18 December 2019 в 05:44
поделиться

Что ж, вы не застрахованы от ошибок с плавающей запятой в Ruby. Например:

irb(main):033:0> (2.01 * 1000).to_i
=> 2009
irb(main):034:0> ((2.01 * 1000.0) + 0.5).floor
=> 2010
0
ответ дан 18 December 2019 в 05:44
поделиться

Конечно, есть!

Пример из Python 2.6:

>>> 1440.0 / 900.0
1.6000000000000001

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

0
ответ дан 18 December 2019 в 05:44
поделиться
Другие вопросы по тегам:

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