Do you have a question? Post it now! No Registration Necessary. Now with pictures!
- Subject
- Posted on
posted on
January 22, 2006, 8:25 am
January 22, 2006, 8:25 am
Dear all,
Currently I am writing a mathematic module which has multiplications
and divisions of very small and big numbers. I use log() and exp() to
handle those problem, but it makes the codes less understandable and
intitutive.
Therefore, I am planning to write a new module to automatically convert
the number into log space (internally) if it is too big or too small.
I hope to ask whether there is already some modules in PERL or C
perform this tasks. Do anyone have some idea?
Thanks in advance.
Tom
Re: Ask for recommended module for precise number
Tom:
See CPAN http://search.cpan.org Math::BigFloat
See also the documentation of
Math::BigRat
Math::FixedPrecision
--
Affijn, Ruud
"Gewoon is een tijger."
Re: Ask for recommended module for precise number
Hi Affijn,
Thanks for pointing the reference. In fact I have browsed those modules
before as well.
However, what I am handling is something like 1e-10000 which is much
smaller than a double can represent. Sometimes I have to use the log
value but sometimes I need to use the real value (e.g., cross entropy).
Or, may I make something wrong where in fact Math:BigFloat is able to
handle those issue as well? Thanks in advance.
Tom
Re: Ask for recommended module for precise number
Tom wrote:
In that case, you really need to read:
http://www.catb.org/~esr/faqs/smart-questions.html
What does double have to do with Math::BigFloat? Did you really read
the CPAN entries?
A casual glance at the pages says "it should work". If you can
demonstrate that it doesn't, then you should have said so in your
original question and maybe you should think about fixing the problem.
--
Jonathan Leffler #include <disclaimer.h>
Email: jleffler@earthlink.net, jleffler@us.ibm.com
Guardian of DBD::Informix v2005.02 -- http://dbi.perl.org /
[OT] quoting (was: Re: Ask for recommended module for precise number)
Tom schreef:
For Tom, and everybody else with "User-Agent: G2/#.#":
"How can I automatically quote the previous message
when I post a reply?"
http://groups.google.co.uk/support/bin/answer.py?answer=14213
See also:
http://www.safalra.com/special/googlegroupsreply /
What's good 'netiquette' when posting to Usenet?
http://groups.google.co.uk/support/bin/answer.py?answer=12348
http://directory.google.com/Top/Computers/Usenet/Etiquette /
But Google needs you to vote for 'Default quoting of
previous message in replies'
http://groups-beta.google.com/support/bin/request.py?contact_type=features
--
Affijn, Ruud
"Gewoon is een tijger."
Re: Ask for recommended module for precise number
.
.
I think " multiplications and divisions of very small and big numbers"
implies "multiple precision arithmetic" - and there are a number of modules
that handle multiple precision arithmetic. These include the Math::Big*
modules (as already mentioned), Math::GMP, Math::Pari and Math::MPFR (to
name a few more).
However, I don't think that any of those modules performs multiple precision
arithmetic (or, in your terms,"multiplications and divisions of very small
and big numbers") by automatically converting "the number into log space"
(or exp space, ftm).
Seems to me that log() and exp() suffer from not being able to precisely
represent many numbers.
For example, the modules mentioned above can all represent *exactly* the
value
''12345678902345678901234567890234567890234567811111190555555555555555555555
5555555555552345678901234567890234567890234567890234567890123456789023456789
0"
How do you represent *exactly* that value by using log() and/or exp() ?
Cheers,
Rob
Re: Ask for recommended module for precise number
Hi Sisyphus,
Thanks a lots for your pointers to those useful library.
I think I did not describe my question well. In fact, I am getting
trouble into some VERY SMALL number which are close to zero. Consider
two number: "a" is 2^(-100) and "b" is 2^(-99). Then, "a/b" is 0.1.
It seems that BigFloat does not work for very small number as follows:
=============================================================
use Math::BigFloat;
use Carp;
my $x = new Math::BigFloat(0.1);
foreach my $i (0..100) {
confess ("It become zero at $i-th iteration") if ($x == 0);
$x = $x * $x;
printf "$i: %.5f\n", $x;
}
=============================================================
The $x in the above program become "0.0" if using original PERL
operations but become "1.0" (wrong number) if using Math::BigFloat.
As I am dealing with values of joint probabilities density, some values
are very very small. Currently I use log() to handle those problems but
it will introduce some errors if I need to do operations (e.g.,
addition) in the real space.
I have a try in GMP after reading your post, but it still convert to
"0.0" after a 10 times of mulitplication of "0.1".
Tom
Sisyphus wrote:
Re: Ask for recommended module for precise number
Tom wrote:
Appearances can be deceiving. The problem appears to be the inability of
printf to format really really small numbers. Replacing your
printf "$i: %.5f\n", $x
with
printf "$i: %s\n", $x->bsstr ()
(gotten from reading the Math::BigFloat docs) I get the following output:
0: 1e-2
1: 1e-4
2: 1e-8
3: 1e-16
4: 1e-32
5: 1e-64
6: 1e-128
7: 1e-256
8: 1e-512
9: 1e-1024
10: 1e-2048
11: 1e-4096
12: 1e-8192
13: 1e-16384
14: 1e-32768
15: 1e-65536
16: 1e-131072
17: 1e-262144
18: 1e-524288
19: 1e-1048576
20: 1e-2097152
21: 1e-4194304
22: 1e-8388608
23: 1e-16777216
24: 1e-33554432
25: 1e-67108864
26: 1e-134217728
27: 1e-268435456
28: 1e-536870912
29: 1e-1073741824
30: 1e-2147483648
31: 1e-4294967296
32: 1e-8589934592
33: 1e-17179869184
34: 1e-34359738368
35: 1e-68719476736
36: 1e-137438953472
37: 1e-274877906944
38: 1e-549755813888
39: 1e-1099511627776
40: 1e-2199023255552
41: 1e-4398046511104
42: 1e-8796093022208
43: 1e-17592186044416
44: 1e-35184372088832
45: 1e-70368744177664
46: 1e-140737488355328
47: 1e-281474976710656
48: 1e-562949953421312
49: 1e-1125899906842624
50: 1e-2251799813685248
51: 1e-4503599627370496
52: 1e-9007199254740992
53: 1e-18014398509481984
54: 1e-36028797018963968
55: 1e-72057594037927936
56: 1e-144115188075855872
57: 1e-288230376151711744
58: 1e-576460752303423488
59: 1e-1152921504606846976
60: 1e-2305843009213693952
61: 1e-4611686018427387904
62: 1e-9223372036854775808
63: 1e-18446744073709551616
64: 1e-36893488147419103232
65: 1e-73786976294838206464
66: 1e-147573952589676412928
67: 1e-295147905179352825856
68: 1e-590295810358705651712
69: 1e-1180591620717411303424
70: 1e-2361183241434822606848
71: 1e-4722366482869645213696
72: 1e-9444732965739290427392
73: 1e-18889465931478580854784
74: 1e-37778931862957161709568
75: 1e-75557863725914323419136
76: 1e-151115727451828646838272
77: 1e-302231454903657293676544
78: 1e-604462909807314587353088
79: 1e-1208925819614629174706176
80: 1e-2417851639229258349412352
81: 1e-4835703278458516698824704
82: 1e-9671406556917033397649408
83: 1e-19342813113834066795298816
84: 1e-38685626227668133590597632
85: 1e-77371252455336267181195264
86: 1e-154742504910672534362390528
87: 1e-309485009821345068724781056
88: 1e-618970019642690137449562112
89: 1e-1237940039285380274899124224
90: 1e-2475880078570760549798248448
91: 1e-4951760157141521099596496896
92: 1e-9903520314283042199192993792
93: 1e-19807040628566084398385987584
94: 1e-39614081257132168796771975168
95: 1e-79228162514264337593543950336
96: 1e-158456325028528675187087900672
97: 1e-316912650057057350374175801344
98: 1e-633825300114114700748351602688
99: 1e-1267650600228229401496703205376
100: 1e-2535301200456458802993406410752
Are those numbers small enough for you? The entire script is appended.
Tom Wyant
use Math::BigFloat;
use Carp;
my $x = new Math::BigFloat(0.1);
foreach my $i (0..100) {
confess ("It become zero at $i-th iteration") if ($x == 0);
$x = $x * $x;
# printf "$i: %.5f\n", $x;
printf "$i: %s\n", $x->bsstr ();
# the following actually works also, but after a while you get
# too many zeros to tell what's going on.
# print "$i: $x\n\n";
}
Re: Ask for recommended module for precise number
Hi Harry,
Thanks for you help. It was really my misunderstanding before. I write
another program which simulate my typical application: calculating
posterior from prior and likelihood, which are very small number.
================================================================
use strict;
use Math::BigFloat;
use Carp;
my $x = new Math::BigFloat(0.1);
my $y = new Math::BigFloat(0.1);
my $num = 100;
foreach my $i (0..$num) {
$x = $x * 0.1;
}
foreach my $j (0..$num-1) {
$y = $y * 0.1;
}
my $z = $x/$y;
printf "z: %.5f\n", $z;
================================================================
Now, the z is "0.1". It fits my usage as those small numbers are only
stored internally. :)
For the printf() issue, it seems to be inconsistency between the string
and the printf() function. I have tried the following tiny program:
================================================================
use strict;
use Carp;
my $i = 0;
while (1) {
my $zeroString = join('', map { "0" } (1..$i));
my $numString = sprintf("0.%s1", $zeroString);
eval {
printf "%d: %.5f\n", $i, $numString;
};
confess ($@) if ($@);
# confess (qq{Convert to "0" at $i-th iterations.\n}) if ($numString
== 0);
$i++;
}
================================================================
With the "commented" statement, the program always output "0.00000"
without error (the program was terminated at 9xxx-th iterations).
With the "commented" statement, the program converts to "0" at around
300 iterations. (it means the Math::BigFloat case is not reproductable
at normal PERL operations?)
Tom
harryfmudd [AT] comcast [DOT] net wrote:
Re: Ask for recommended module for precise number
Tom wrote:
No problem. Harry Mudd is a quasi-alias (quasi- because I always sign my
real name), and a character from the original Star Trek. It was intended
to be thrown away when it started collecting too much spam, but so far I
haven't done that. Though I'm tempted daily.
[snip! /]
I think we can conclude that printf is simply not going to work right
with Math::BigFloat numbers.
The bottom line is that Math::BigFloat is _almost_ magic. I have not
used it much, but I get the impression that as long as you're so-called
"pure Perl" you're OK. That is, if you write a script using BigFloat,
and don't invoke any functions that you didn't write in Perl, you're
fine. If you invoke built-ins (for example, log (), sin (), and so
forth) or libraries that do "C" call-outs, you don't get arbitrary
precision. At least, that's my explanation for printf's behaviour.
Even if Math::BigFloat were fully magic and worked for the built-ins,
transcendental functions like log () and sin () would still be unusable,
because the calculation would never terminate.
If you read the Math::BigFloat docs, you will find methods to "take
apart" BigFloat numbers, and I suppose you (or someone) could write
arbitrary-precision functions to replace the built-ins. Precision of
transcendental functions would have to be specified "up front" in some
way, to prevent atan2 (1, 0) from trying to compute the last digit of pi.
Whether this has been done I don't know. I personally would hesitate to
do it because I don't need it, and therefore it would be inadequately
tested.
If I could change the subject briefly, I'd like to make a couple
comments on Perl style:
* You don't need to "use Carp" and then "confess" unless you're
interested in a full call stack trace. The "die" command also terminates
your program with a message. If the message does not end in "\n", Perl
appends the line number of the "die".
* For a string of $i zeros, you can say '0' x $i instead of using join
(), and I think you'll find it is more efficient.
* Similarly, for large numbers of iterations, "for (i = 0; i < $num;
$i++)" would be preferred to "foreach $i (0 .. $num)", because the "0 ..
$num" actually builds a list of all the numbers, which might be a bad
thing if $num were something like 1e9.
Tom Wyant
Re: Ask for recommended module for precise number
harryfmudd [AT] comcast [DOT] net wrote:
No, it doesn't. At least, not in any reasonably recent version of
Perl. foreach() over a range now evaluates the list "lazilly" and does
not build a list of integers to iterate over.
for (0.. $num) is far preferred to for ($i = 0; $i<=$num; $i++) for
readability, maintainability, and lazy typing.
Paul Lalli
Re: Ask for recommended module for precise number
Hi Harry,
In fact those number are required to interact with a conjugate gradient
library in C++.
I tried to write a simple program in C and then use SWIG to generate
the PERL interface:
===============================================================
C:
double addOne(double x)
{
double y = x + 1.0;
return y;
}
===============================================================
PERL:
my $x = new Math::BigFloat(0.1);
$x = addOne($x);
printf "%.5f\n", $x;
===============================================================
It is amazing that it output "1.10000" to me !
After that I modify the program as:
===============================================================
PERL:
my $x = new Math::BigFloat(0.1);
foreach my $i (0..99) {
$x = $x * 0.1;
}
my $x = 10.0;
$x = Simplest::addOne($x);
printf "%.5f\n", $x;
===============================================================
And it can output "1.00000" to me!
Tom
harryfmudd [AT] comcast [DOT] net wrote:
Re: Ask for recommended module for precise number
Yes - I was surprised by that, too. I get the same when I run the following
script:
-- start --
use Math::BigFloat;
use warnings;
use Inline C => Config =>
BUILD_NOISY => 1; # see any compiler warnings
use Inline C => <<'EOC';
double addOne(double x)
{
double y = x + 1.0;
return y;
}
EOC
my $x = new Math::BigFloat(0.1);
$x = addOne($x);
printf "%.5f\n", $x;
__END__
-- end --
If you have Inline::C installed, then you'll be able to run that script,
too.
What's I find surpising is that you (and I) are able to pass a
Math::BigFloat object to a C function that takes a *double* as its argument,
and not get an error. Furthermore, addOne() also gets hold of the *correct*
value. I don't know exactly how that is achieved. It seems that when you do
'addOne($x);', where $x is a Math::BigFloat object then addOne() receives,
as its argument, whatever it is that the overloaded string operator ("")
returns for $x. I think this would always be the value you see when you
'print $x;'.
The same thing happens with other modules (eg Math::GMP) which use
overloading. That is, I can succesfully 'addOne($x);' where $x is a
Math::GMP object.
With Math::MPFR the overloaded string operator returns values in the form
'.127@2' - instead of the usual '12.7'. If I 'addOne($x);' where $x is a
Math::MPFR object that has the value of (say) 1.2, then I get the warning:
Argument ".12@1" isn't numeric in subroutine entry .....
and the argument that addOne() receives in this case is '0.12' instead of th
e desired '1.2'. (Note that when perl treats a string as a number it ignores
the first "garbage" character it finds, and anything that comes after that
"garbage" character. The first "garbage" character in '.12@1' is the "@",
so perl ignores it and everything that follows it - leaving just the number
'.12'.)
If Math::MPFR's overload string function returned the value as '1.2' instead
of '.12@1', then Math::MPFR objects could be passed successfully to addOne()
in exactly the same way as happens with Math::BigFloat.
I don't see how that is possible - and I get exactly what I expect to get:
11.00000
Or, if warnings are enabled I get:
"my" variable $x masks earlier declaration in same scope at try.pl line 24.
11.00000
which is also to be expected.
Cheers,
Rob
Site Timeline
- » ISpell Issues
- — Next thread in » PERL Modules Announcements
- » Compilation problem using make
- — Previous thread in » PERL Modules Announcements
- » Updating the hash across the files
- — Newest thread in » PERL Modules Announcements
- » Anyone Using ESET NOD32??
- — The site's Newest Thread. Posted in » Anti-Virus Software