Возможно обработать осведомленное о локали "Да / Никакой выбор" в оболочке 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
Я бы не согласился с Лутцем ... Хотя упомянутые вами ошибки округления существуют в Python / Perl / Ruby, они не имеют абсолютно отношения к языкам. реализуется на C. Проблема идет глубже.
Числа с плавающей запятой, как и все данные, на современных компьютерах представлены в двоичном формате. Так же, как есть числа с периодическим десятичным представлением (например, 1/3 = 0,333333 ...), есть также числа с периодическим двоичным представлением (например, 1/10 = 0,0001100110011 ...). Поскольку эти числа не могут быть точно представлены в (ограниченном объеме) памяти компьютера, любые вычисления, связанные с ними, приведут к ошибке.
Это можно обойти, используя высокоточные математические библиотеки, которые представляют числа либо как два числа. дроби (например, «числитель = 1,
В 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 требует, чтобы вы сделали явный выбор того, что вы хотите от своих чисел.
Более того, это большое недоразумение, что точная арифметика не приводит к проблемам с округление. Каждый раз, когда вы округляете точное значение, чтобы сделать с ним что-то полезное для пользователя - например, распечатать его для пользователя или добавить столько долларов на банковский счет пользователя - вы сталкиваетесь со «странным поведением» округления. Это свойственно нецелочисленной арифметике.
Каждый раз, когда вы округляете точное значение, чтобы сделать с ним что-то полезное для пользователя - например, распечатайте его для пользователя или добавьте столько долларов на банковский счет пользователя - вы сталкиваетесь со «странным поведением» округления. Это свойственно нецелочисленной арифметике. Каждый раз, когда вы округляете точное значение, чтобы сделать с ним что-то полезное для пользователя - например, распечатать его для пользователя или добавить столько долларов на банковский счет пользователя - вы сталкиваетесь со «странным поведением» округления. Это свойственно нецелочисленной арифметике. Это зависит от обстоятельств. 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
Также, как и ожидалось, это не выполняется в одной инструкции ЦП.
Поскольку реализован базовый интерпретатор как CPython, так и Perl в C они ведут себя как программа C.
Это зависит от того, как вы представляете свои числа, а не от используемого вами языка.
Например, если я пишу весь свой код на ассемблере 8051, но реализовал изящную библиотеку рациональных чисел, тогда округление не проблема. 1/3 равняется только 1/3.
Однако, если я использую последний шикарный динамический язык, и в нем используются числа с плавающей запятой IEE754, тогда применяются все ограничения IEEE754.
Если вам нужно заботиться о деталях чисел, которые вы генерируете, то вам нужно понять их представление и то, как ими манипулируют с помощью выбранных вами инструментов.
PDL - популярная библиотека для выполнения научных вычислений на Perl.
Когда вы занимаетесь научным программированием, вам всегда придется беспокоиться об ошибках округления, независимо от того, какой язык программирования или числовую библиотеку вы используете.
Доказательство: Допустим, вы хотите отслеживать движение молекулы у границы Вселенной. Размер Вселенной составляет около 93 миллиардов световых лет (насколько нам известно). Молекула довольно крошечная, поэтому вам понадобится как минимум нанометровая точность (10 ^ -6). Это 50 порядков.
По какой-то причине вам нужно повернуть эту молекулу. Это включает операции sin ()
и cos ()
и умножение. Умножение не является проблемой, поскольку количество действительных цифр - это просто сумма длин обоих операндов. Но как насчет sin ()
?
Вы должны создать уравнение ошибки, чтобы быть уверенным, что вы сохраняете достаточное количество цифр, чтобы окончательный результат имел известную максимальную ошибку. Я не знаю ни одной «простой» числовой библиотеки, которая могла бы выполнять эту операцию автоматически (скажем, как часть вызова sin ()
). Здесь вам понадобится Matlab или что-то подобное.
Вы можете выполнять вычисления с множественной точностью с помощью Python с помощью внешних модулей. В разделе Multi Precision Math на официальном веб-сайте перечислены многие из них.
Что ж, вы не застрахованы от ошибок с плавающей запятой в Ruby. Например:
irb(main):033:0> (2.01 * 1000).to_i
=> 2009
irb(main):034:0> ((2.01 * 1000.0) + 0.5).floor
=> 2010
Конечно, есть!
Пример из Python 2.6:
>>> 1440.0 / 900.0
1.6000000000000001
Как говорит Лутц, поскольку языки сценариев часто реализуются на C, они наследуют эти «возможности». Их компенсация на языке, несомненно, означала бы некоторый компромисс в производительности или переносимости.