LINUX.ORG.RU

Странности perl.


0

1

Накалякал програмку для вычисления корня n-ной степени из a на перле (да, наверное не для того он, но я как раз его учу, и, кроме того, компилировать ничего не надо)

#!/usr/bin/perl

use warnings;
use strict;
use 5.010;

my $base = $ARGV[0]
        // die "Usage $0 <base> <power> <quality>\n";
my $power = $ARGV[1]
        // die "Usage $0 <base> <power> <quality>\n";
my $req_quality = $ARGV[2]
        // die "Usage $0 <base> <power> <quality>\n";

# Получаем из командной строки основание, степень  точность в качестве аргументов.

my $quality = 1;        # "Качество" - точность вычисления.
my $start = 0;          # Нижняя граница числа
my $stop = $base;       # Верхняя граница числа

while ($quality >= $req_quality) {
        #Пока точность не достигает требуемой
        while ($stop-$start >= 2*$quality) {
                $start += $quality if ($start+$quality)**$power < $base;
                $stop -= $quality if ($stop-$quality)**$power > $base;
                #Сдвигаем нижнюю и верхнюю границу числа
                #Пока не подберемся вплотную к значению радикала,
        }
        print "start = $start, stop = $stop, stop - start =", $stop-$start, "\n";
        $quality /= 10;
        #Увеличиваем точность;
}

my $result = ($start + $stop)/2;

say "Result: $result in the power of $power equals ", $result**$power;
#Печатаем результат и одновременно с этим проверяем, что получилось;

Все бы хорошо, кроме этой строчки:

while ($stop-$start >= 2*$quality)
Мне пришлось сделать так, а не так:
while ($stop-$start > $quality)
поскольку, перл как-то странно считает разность. Я специально добавил print после каждого подсчета, чтобы продемонстрировать это:
$ ./radical.pl 5 70 0.000000001
start = 1, stop = 2, stop - start =1
start = 1, stop = 1.2, stop - start =0.199999999999999
start = 1.02, stop = 1.04, stop - start =0.0199999999999991
start = 1.023, stop = 1.024, stop - start =0.00100000000000122
start = 1.0232, stop = 1.0233, stop - start =0.000100000000001321
start = 1.02325, stop = 1.02326, stop - start =1.00000000007316e-05
start = 1.023258, stop = 1.023259, stop - start =1.00000000147205e-06
start = 1.0232583, stop = 1.0232584, stop - start =1.00000000946565e-07
start = 1.02325832, stop = 1.02325833, stop - start =1.00000014935375e-08
start = 1.023258322, stop = 1.023258323, stop - start =1.00000074887419e-09
Result: 1.0232583225 in the power of 70 equals 4.99999985235406
В чем дело? Почему 1.04 - 1.02 == 0.0199999999999991?



Последнее исправление: IceAlchemist (всего исправлений: 1)

платиновые дебил-треды development

ман IEEE 754

anonymous
()

Сенсация! Новое открытие безумных ученых!

1.04 - 1.02 == 0.0199999999999991

Zorn
()

В чем дело? Почему 1.04 - 1.02 == 0.0199999999999991?

Абсолютной точности не бывает.

</thread>

Deleted
()
Ответ на: комментарий от Bad_ptr
 clisp -x '(- 1.04 1.02)'
  i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo
  I I I I I I I      8     8   8           8     8     o  8    8
  I  \ `+' /  I      8         8           8     8        8    8
   \  `-+-'  /       8         8           8      ooooo   8oooo
    `-__|__-'        8         8           8           8  8
        |            8     o   8           8     o     8  8
  ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8

Добро пожаловать GNU CLISP 2.49 (2010-07-07) <http://clisp.cons.org/>

Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2010

Напечатайте :h и нажмите Ввод для получения справки.

0.01999998
До свидания! Не поминайте лихом!
Bad_ptr ★★★★★
()

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

IceAlchemist
() автор топика

недоязыков тред. а в сишечке всё правильно:

$ gcc -xc -O0 - <<<'#include <stdio.h>
> int main(){ float a = 1.04, b = 1.02; printf("%.2f\n", a - b); }'; ./a.out
0.02

anonymous
()
Ответ на: комментарий от Bad_ptr

*озираясь по сторонам*

Не, я ничего страшнее схемы не принимал.

PolarFox ★★★★★
()
Ответ на: комментарий от anonymous

недоязыков тред. а в сишечке всё правильно

php > print 1.04 - 1.02;
0.02
Bad_ptr ★★★★★
()
Ответ на: комментарий от anonymous

недоязыков тред. а в сишечке всё правильно:

$ gforth -e '1.04e 1.02e f- f. cr bye'
0.02 
anonymous
()
Ответ на: комментарий от anonymous

недоязыков тред. а в сишечке всё правильно:

Тут не в языке дело.

#include <stdio.h>

int main()
{ 
  float a = 1.04, b = 1.02;
  printf("%.16f\n", a - b);
}
$ ./testtest 
0.0199999809265137
Deleted
()
Ответ на: комментарий от PolarFox

Что это за менора

У clisp в ньюсгруппе была жаркая баталия на эту тему. В смысле пользователи спрашивали почему именно менора, а разработчики(сами себя они называют не иначе как хакеры...) строили из себя целочек говорили, что это никак не связано c религией/политикой, но и сказать они не могут, потому что это личное.

А через какое-то время на сайте появилось объяснение, что-то связанное со светом, «CL несет в себе свет»... точно не помню и лень искать ;]

beka
()
Ответ на: комментарий от PolarFox

Что это за менора о_О

Канделябр же!

anonymous
()
gosha@bugtop:~/tmp$ perl -MMath::BigFloat -e 'print 1.04 - 1.02'
0.02

Всем чмоки в этом чатике :)

И да, про погрешность компа всё правильно сказали.

helios ★★★★★
()

irb(main):010:0> 1.04 - 1.02 => 0.020000000000000018

anonymous
()
Ответ на: комментарий от IceAlchemist

Да так-то он и без модулей нормально работает...

Упс... Таки впилили сразу? Good, good!

helios ★★★★★
()
Ответ на: комментарий от IceAlchemist

потому, что print округляет до 6 знаков после запятой, которые

number of decimal digits, q, such that any floating-point number with q decimal digits
can be rounded into a floating-point number with p radix b digits and back again
without change to the q decimal digits

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

$ perl -e 'printf "%.17f\n", 1.04 - 1.02'
0.02000000000000002
$ _
arsi ★★★★★
()
Ответ на: комментарий от baverman

Давай к нам

Не дёргайте вы человека! Пусть сначала нормально изучит Perl, а потом...
...воротит нос от Python'а :-D

helios ★★★★★
()
Ответ на: комментарий от baverman

Кстати, в перле из коробки есть работа с числами произвольной точности?

Всё, нашел. На первый взгляд, сделано клево.

baverman ★★★
()
Ответ на: комментарий от baverman

> из коробки

что ты подразумеваешь под «из коробки»? встроенные в язык? в базовых модулях?

$ man perlmodlib
....
Standard Modules
....
       Math::BigFloat
                   Arbitrary size floating point math package

       Math::BigInt
                   Arbitrary size integer/float math package

       Math::BigRat
                   Arbitrary big rational numbers
....
arsi ★★★★★
()

вот тебе еще одно разочарование, весьма эффектное

$ perl -e 'printf "%.20f\n", 1.1 - 1E-16'
1.10000000000000008882

anonymous
()
Ответ на: комментарий от baverman

Работает после cd perl && ./configure && make install

Кстати, в Perl есть и нормальный пакетный менеджер, дабы не бегать по инетам, не искать модули.

Come to the Dark Side! We have a CPAN =^_^=

helios ★★★★★
()
Ответ на: комментарий от baverman

> Работает после cd perl && ./configure && make install

ок, модули из «man perlmodlib» удовлетворяют условиям :)

arsi ★★★★★
()
Ответ на: комментарий от Bad_ptr

В питоне тоже наверняка есть костыль какой-нибудь :).

Два, как минимум.

jessey
()
Ответ на: комментарий от baverman

Вообще-то я прочитал про «decimal strings», или у них проблемы с приведением на арифметике?

Где прочитал? УМВР

perl -MMath::BigInt -le 'print Math::BigInt->new(12345678901234567890)'
12345678901234567890
perl -MMath::BigInt -le 'print Math::BigInt->new(«12345678901234567890»)'
12345678901234567890

helios ★★★★★
()
Ответ на: комментарий от helios

perldoc perlnumber

Similarly, decimal strings can represent only those numbers which have a finite decimal expansion. Being strings, and thus of arbitrary length, there is no practical limit for the exponent or number of decimal digits for these numbers. (But realize that what we are discussing the rules for just the storage of these numbers. The fact that you can store such «large» numbers does not mean that the operations over these numbers will use all of the significant digits.

baverman ★★★
()
Ответ на: комментарий от baverman
cpan[3]> help

Display Information                                                (ver 1.9456)
 command  argument          description
 a,b,d,m  WORD or /REGEXP/  about authors, bundles, distributions, modules
 i        WORD or /REGEXP/  about any of the above
 ls       AUTHOR or GLOB    about files in the author's directory
    (with WORD being a module, bundle or author name or a distribution
    name of the form AUTHOR/DISTRIBUTION)

Download, Test, Make, Install...
 get      download                     clean    make clean
 make     make (implies get)           look     open subshell in dist directory
 test     make test (implies make)     readme   display these README files
 install  make install (implies test)  perldoc  display POD documentation

Upgrade
 r        WORDs or /REGEXP/ or NONE    report updates for some/matching/all modules
 upgrade  WORDs or /REGEXP/ or NONE    upgrade some/matching/all modules

Pragmas
 force  CMD    try hard to do command  fforce CMD    try harder
 notest CMD    skip testing

Other
 h,?           display this menu       ! perl-code   eval a perl command
 o conf [opt]  set and query options   q             quit the cpan shell
 reload cpan   load CPAN.pm again      reload index  load newer indices
 autobundle    Snapshot                recent        latest CPAN uploads

С чем будем сравнивать? :)

helios ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.