How do I delete my blog?
Smooth numeric upgrades?
Hello Guest
  
  • Login
• Register…
• Start blog
  • Who, Where, When
• What can I do?
• What to Read?
  • Polls
• Avatars
• Interests
  • Cities and Countries
• Random blog
• Users search
  • Search
• Games
• Tests
• QAIX
  • Сообщества
• Talxy Chat
• Horoscope
• Online
 
Зарегистрируйся!

QAIX > Perl web-programming > Smooth numeric upgrades? 21 October 2008 03:54:29

  Recent blog posts: 
  They have birthday today: 
  Forums:   
  Discuss: 
  Recent forum topics: 
  Recent forum comments:
  Moderators:

Smooth numeric upgrades?

Michael G Schwern 21 October 2008 03:54:29
 What's the status of numeric upgrades in Perl 6? Is see the docs say "Perl 6
intrinsically supports big integers and rationals through its system of type
declarations. Int automatically supports promotion to arbitrary precision" but
it looks like it's doing the same thing as Perl 5.

$ ./perl6 -e 'say 2**40'
1099511627776

$ ./perl6 -e 'say 2**50'
1.12589990684262e+1­5

$ ./perl6 -e 'say 2**1100'
inf

And...

$ ./perl6 -e 'my Int $foo = 2**32; say $foo'
Type check failed
current instr.: 'parrot;Perl6Object­;infix:=' pc 60 (src/gen_builtins.p­ir:52)
called from Sub '_block11' pc 98 (EVAL_12:41)
called from Sub 'parrot;PCT::HLLCom­piler;eval' pc 806
(src/PCT/HLLCompile­r.pir:480)
called from Sub 'parrot;PCT::HLLCom­piler;command_line' pc 1298
(src/PCT/HLLCompile­r.pir:707)
called from Sub 'parrot;Perl6::Comp­iler;main' pc 17029 (perl6.pir:172)
perl6(4325) malloc: *** Deallocation of a pointer not malloced: 0x4157170;
This could be a double free(), or free() called with the middle of an
allocated block; Try setting environment variable MallocHelp to see tools to
help debug
perl6(4325) malloc: *** Deallocation of a pointer not malloced: 0xda71b; This
could be a double free(), or free() called with the middle of an allocated
block; Try setting environment variable MallocHelp to see tools to help debug
Bus error (core dumped)

though hopefully that's transient.


--
"Clutter and overload are not an attribute of information,
they are failures of design"
-- Edward Tufte

Add comment
Larry Wall 4 October 2008 08:47:38 permanent link ]
 On Fri, Oct 03, 2008 at 11:57:30PM -0400, Michael G Schwern wrote:
: What's the status of numeric upgrades in Perl 6? Is see the docs say "Perl 6
: intrinsically supports big integers and rationals through its system of type
: declarations. Int automatically supports promotion to arbitrary precision" but
: it looks like it's doing the same thing as Perl 5.
:
: $ ./perl6 -e 'say 2**40'
: 1099511627776
:
: $ ./perl6 -e 'say 2**50'
: 1.12589990684262e+1­5
:
: $ ./perl6 -e 'say 2**1100'
: inf

The status of numeric upgrades in Perl 6 is fine. It's rakudo that
doesn't do so well. :)­

As another datapoint:

$ pugs -e 'say 2**40'
1099511627776
$ pugs -e 'say 2**50'
1125899906842624
$ pugs -e 'say 2**1100'
1358298529049385849­27735142835926677860­34938469317445497485­19669727813092754241­84872053920832075605­92298578262953847383­47503872554323492997­11555483428006287218­85763499406390331782­86414416468073076683­71605262231765127984­35772129956553355286­03220308038077575973­23201989850948840040­69116123084147875437­18365846746514894879­0552744165376

I don't think of Int as a type that automatically upgrades. I think
of it as an arbritrarily large integer that the implementation can in
some cases choose to optimize to a smaller or faster representation,
but only if that can be transparent to the user (apart from the size
and speed effects). Certainly this should be the case for anything
declared "Int". A native "int" is another matter, but that's just
a storage constraint, and probably shouldn't influence intermediate
computations, which are done in Int. So it shouldn't matter whether 2
and 1100 are stored in Int or int form; the result should be the same
(subject, perhaps to pragmatic control of temp types).

Larry
Add comment
Michael G Schwern 4 October 2008 10:06:18 permanent link ]
 Larry Wall wrote:
On Fri, Oct 03, 2008 at 11:57:30PM -0400, Michael G Schwern wrote:
: What's the status of numeric upgrades in Perl 6? Is see the docs say "Perl 6
: intrinsically supports big integers and rationals through its system of type
: declarations. Int automatically supports promotion to arbitrary precision" but
: it looks like it's doing the same thing as Perl 5.
:
: $ ./perl6 -e 'say 2**40'
: 1099511627776
:
: $ ./perl6 -e 'say 2**50'
: 1.12589990684262e+1­5
:
: $ ./perl6 -e 'say 2**1100'
: inf
The status of numeric upgrades in Perl 6 is fine. It's rakudo that
doesn't do so well. :)­
As another datapoint:
$ pugs -e 'say 2**40'
1099511627776
$ pugs -e 'say 2**50'
1125899906842624
$ pugs -e 'say 2**1100'
1358298529049385849­27735142835926677860­34938469317445497485­19669727813092754241­84872053920832075605­92298578262953847383­47503872554323492997­11555483428006287218­85763499406390331782­86414416468073076683­71605262231765127984­35772129956553355286­03220308038077575973­23201989850948840040­69116123084147875437­18365846746514894879­0552744165376

That's good [1] to hear, thanks.


I don't think of Int as a type that automatically upgrades. I think
of it as an arbritrarily large integer that the implementation can in
some cases choose to optimize to a smaller or faster representation,

Oh don't worry, I do. I just got so flustered when I saw Rakudo do the same
thing that Perl 5 does I was worried this got lost somewhere along the line.


[1] We need a polite way to say "less bad".


--
The mind is a terrible thing,
and it must be stopped.
Add comment
Tom Christiansen 4 October 2008 13:37:09 permanent link ]
 In-Reply-To: Message from Michael G Schwern <schwern@pobox.com>­
of "Sat, 04 Oct 2008 02:06:18 EDT." <48E707DA.3070706@p­obox.com>

Larry Wall wrote:
The status of numeric upgrades in Perl 6 is fine. It's rakudo that
doesn't do so well. :)­
As another datapoint:
$ pugs -e 'say 2**40'
1099511627776
$ pugs -e 'say 2**50'
1125899906842624
$ pugs -e 'say 2**1100'
1358298529049385849­27735142835926677860­34938469317445497485­19669727813<SNIP>

That's good [1] to hear, thanks.

I don't think of Int as a type that automatically upgrades. I think
of it as an arbitrarily large integer that the implementation can in
some cases choose to optimize to a smaller or faster representation,

Oh don't worry, I do. I just got so flustered when I saw Rakudo do the
same thing that Perl 5 does I was worried this got lost somewhere along
the line.

[1] We need a polite way to say "less bad".

!
ah
fab
yay
good
cool
ayup
d'oh!
helps
tasty
yummy
smooth
cheers
better
yippee!
soothes
pleases
niftier
relieves
mediates
inspires
mollifies
mitigates
clarifies
my mistake
oh, right!
grrrrreat!
delightful
not to worry
oh be joyful!
'tain't so bad
calms my qualms
less sub-optimal
cheers my spirit
soothes my nerves
dispells my doubts
heartens my resolve
cushions the cudgel
dismisses my dismay
drives out the dread
comforts me to learn
inspires me with hope
restores my confidence
gladdens my good humor
brightens my rainy day
alleviates my concerns
mollifies my misgivings
alleviates my confusion
puts down the false alarm
perks/plucks up my courage
pacifies my preoccupations
banishes my paranoia-demons
felicitates my facilitation
facilitates my felicitation
assuages my misapprehensions
shows I was worrying too much
encourages me; is encouraging
warms the cockles of my heart
offers hope for a better world
trounces my tetchy trepidations
dispells my misplaced anxieties
sure puts a spiffier shine on it
makes molehills out of mountains
eases up on my nerves a fair bit
not nearly so gnarly as I'd feared
'tis not too late to seek a newer world
way better than I'd half-begun to suspect
patches the potholes in my crumbling wetware
softens the imagined blow that wasn't even there to start with
serenades such sweet sonnets as to nullify nervous nellies' natterings
Add comment
Patrick R. Michaud 4 October 2008 18:41:22 permanent link ]
 On Fri, Oct 03, 2008 at 09:47:38PM -0700, Larry Wall wrote:
On Fri, Oct 03, 2008 at 11:57:30PM -0400, Michael G Schwern wrote:
: What's the status of numeric upgrades in Perl 6? Is see the
: docs say "Perl 6 intrinsically supports big integers and rationals
: through its system of type declarations. Int automatically
: supports promotion to arbitrary precision" but it looks like it's
: doing the same thing as Perl 5.
The status of numeric upgrades in Perl 6 is fine. It's rakudo that
doesn't do so well. :)­

Correct. I suspect that eventually the Rakudo developers will have
to develop a custom set of PMCs for Perl 6 behaviors rather than
relying on the Parrot ones.

In the more general sense, it's sometimes useful to remember that
Parrot is a virtual machine that often takes a Perl 5 approach to
solving problems -- I suspect because in many cases the "Perl 6"
approach wasn't necessarily well defined at the time. It's going
to take Rakudo a little time to layer or rebuild the correct
semantics for its core object types, so in the meantime we see
bits of Parrot peeking out through the interfaces.

Pm
Add comment
Bob Rogers 4 October 2008 22:21:56 permanent link ]
 From: "Patrick R. Michaud" <pmichaud@pobox.com­>
Date: Sat, 4 Oct 2008 09:41:22 -0500

On Fri, Oct 03, 2008 at 09:47:38PM -0700, Larry Wall wrote:
On Fri, Oct 03, 2008 at 11:57:30PM -0400, Michael G Schwern wrote:
: What's the status of numeric upgrades in Perl 6? Is see the
: docs say "Perl 6 intrinsically supports big integers and rationals
: through its system of type declarations. Int automatically
: supports promotion to arbitrary precision" but it looks like it's
: doing the same thing as Perl 5.
The status of numeric upgrades in Perl 6 is fine. It's rakudo that
doesn't do so well. :)­

Correct. I suspect that eventually the Rakudo developers will have
to develop a custom set of PMCs for Perl 6 behaviors rather than
relying on the Parrot ones.

The Parrot behavior in this case may be closer than you think. After
applying the patch below, I get the expected output from Rakudo:

rogers@rgr> ./perl6 -e 'say 2**40'
1099511627776
rogers@rgr> ./perl6 -e 'say 2**50'
1125899906842624
rogers@rgr> ./perl6 -e 'say 2**1100'
1358298529049385849­27735142835926677860­34938469317445497485­19669727813092754241­84872053920832075605­92298578262953847383­47503872554323492997­11555483428006287218­85763499406390331782­86414416468073076683­71605262231765127984­35772129956553355286­03220308038077575973­23201989850948840040­69116123084147875437­18365846746514894879­0552744165376
rogers@rgr>

It does produces >300 spectest_regression­ failures, though, so I don't
claim the patch is right.

Parrot doesn't currently downgrade BigInt PMCs to Integer when it
should, though.

-- Bob Rogers
http://rgrjr.dyndns­.org/



Make <infix:*­*> and <infix:*­> DTRT for Int => BigInt promotion. May
break other numeric behaviors.

Index: languages/perl6/src­/builtins/op.pir
===================­====================­====================­========
--- languages/perl6/src­/builtins/op.pir (revision 31592)
+++ languages/perl6/src­/builtins/op.pir (working copy)
@@ -59,21 +59,12 @@

## exponentiation
.sub 'infix:*­*' :multi(_,_)
- .param num base
- .param num exp
- $N0 = pow base, exp
- .return ($N0)
+ .param pmc base
+ .param pmc exp
+ $P0 = n_pow base, exp
+ .return ($P0)
.end

-
-.sub 'infix:*­*' :multi(Integer,Inte­ger)
- .param num base
- .param num exp
- $N0 = pow base, exp
- .return '!upgrade_to_num_if­_needed'($N0)
-.end
-
-
## symbolic unary
.sub 'prefix:!' :multi(_)
.param pmc a
@@ -140,21 +131,13 @@

## multiplicative
.sub 'infix:*­' :multi(_,_)
- .param num a
- .param num b
- $N0 = a * b
- .return ($N0)
+ .param pmc a
+ .param pmc b
+ $P0 = n_mul a, b
+ .return ($P0)
.end


-.sub 'infix:*­' :multi(Integer,Inte­ger)
- .param num a
- .param num b
- $N0 = a * b
- .return '!upgrade_to_num_if­_needed'($N0)
-.end
-
-
.sub 'infix:/' :multi(_,_)
.param num a
.param num b
Add comment
Patrick R. Michaud 5 October 2008 03:15:57 permanent link ]
 On Sat, Oct 04, 2008 at 05:09:47PM -0400, Bob Rogers wrote:
Content-Description­: message body text
From: "Patrick R. Michaud" <pmichaud@pobox.com­>
Date: Sat, 4 Oct 2008 09:41:22 -0500
On Fri, Oct 03, 2008 at 09:47:38PM -0700, Larry Wall wrote:
On Fri, Oct 03, 2008 at 11:57:30PM -0400, Michael G Schwern wrote:
: What's the status of numeric upgrades in Perl 6? Is see the
: docs say "Perl 6 intrinsically supports big integers and rationals
: through its system of type declarations. Int automatically
: supports promotion to arbitrary precision" but it looks like it's
: doing the same thing as Perl 5.
The status of numeric upgrades in Perl 6 is fine. It's rakudo that
doesn't do so well. :)­
Correct. I suspect that eventually the Rakudo developers will have
to develop a custom set of PMCs for Perl 6 behaviors rather than
relying on the Parrot ones.
The Parrot behavior in this case may be closer than you think. After
applying the patch below, I get the expected output from Rakudo:
rogers@rgr> ./perl6 -e 'say 2**40'
1099511627776
rogers@rgr> ./perl6 -e 'say 2**50'
1125899906842624
[...]
It does produces >300 spectest_regression­ failures, though, so I don't
claim the patch is right.

One of the big problems with Parrot's n_* opcodes is that they
often assume that the type of the result should be the same as
the type of the first operand. So, given (Perl 6) code like

my @a = <abc def>;
say @a * 2147483648;

the PIR translation using n_mul fails because it doesn't
know how to n_mul a ResizablePMCArray:

$ cat v.pir
.sub main
## Perl 6: my @a = <abc def>;
.local pmc a
a = new 'ResizablePMCArray'­
a[0] = 'abc'
a[1] = 'def'

## Perl 6: say @a * 2147483648
$P1 = n_mul a, 2147483648
say $P1
.end
$ ./parrot v.pir
MMD function __multiply not found for types (58, -99)
current instr.: 'main' pc 11 (v.pir:9)
$

All of the mechanisms I've been able to find in Parrot for
converting an arbitrary PMC to a number seem to result in
the code for infix:<*> that we have now. I'm open for
suggestions to improve this, though.

Pm
Add comment
Bob Rogers 5 October 2008 06:08:10 permanent link ]
 From: "Patrick R. Michaud" <pmichaud@pobox.com­>
Date: Sat, 4 Oct 2008 18:15:57 -0500

One of the big problems with Parrot's n_* opcodes is that they
often assume that the type of the result should be the same as
the type of the first operand . . .

I kinda thought it wouldn't be that easy. Sigh.

All of the mechanisms I've been able to find in Parrot for
converting an arbitrary PMC to a number seem to result in
the code for infix:<*> that we have now. I'm open for
suggestions to improve this, though.

Pm

Hmm. My instinct would be to rely on MMD:

.sub 'infix:*­' :multi(Perl6Array,_­)
.param pmc a
.param pmc b
$P0 = new 'Integer'
$P0 = a
.return 'infix:*­'($P0, b)
.end

.sub 'infix:*­' :multi(_,Perl6Array­)
.param pmc a
.param pmc b
$P0 = new 'Integer'
$P0 = b
.return 'infix:*­'(a, $P0)
.end

This exposes an MMD bug (it runs forever), but something like this
should work once it's fixed.

-- Bob
Add comment
Darren Duncan 5 October 2008 06:23:42 permanent link ]
 Patrick R. Michaud wrote:
Correct. I suspect that eventually the Rakudo developers will have
to develop a custom set of PMCs for Perl 6 behaviors rather than
relying on the Parrot ones.

I think it would be better for things like unlimited-precision­ integers and
rationals to be Parrot generic PMCs rather than Perl 6 specific ones, since
there are other languages that also have unlimited-precision­ numbers (for
example Python afaik) and it would be better to have a common
implementation. Several popular languages have unlimiteds now, and more
are coming over time.

Note that just as integers are naturally radix independent, the unlimited
rationals should be too, and the latter can compactly represent all
rationals as a triple of integers corresponding roughly to a (normalized)
[mantissa, radix, exponent] triple; with that approach you also get
unlimited floats for free, so no reason to make floats an exception where
they aren't unlimited where integers and other rationals are; after all,
what is a float or scientific notation than just another notation for a
rational value literal.

-- Darren Duncan
Add comment
Patrick R. Michaud 5 October 2008 06:57:35 permanent link ]
 On Sat, Oct 04, 2008 at 10:08:10PM -0400, Bob Rogers wrote:
Hmm. My instinct would be to rely on MMD:
.sub 'infix:*­' :multi(Perl6Array,_­)
.param pmc a
.param pmc b
$P0 = new 'Integer'
$P0 = a
.return 'infix:*­'($P0, b)
.end
.sub 'infix:*­' :multi(_,Perl6Array­)
.param pmc a
.param pmc b
$P0 = new 'Integer'
$P0 = b
.return 'infix:*­'(a, $P0)
.end
This exposes an MMD bug (it runs forever), but something like this
should work once it's fixed.

Unfortunately this approach means we'd have to write a separate
:multi for nearly every type and operator combination, including
potentially the user-defined ones.

Pm
Add comment
Bob Rogers 5 October 2008 07:13:12 permanent link ]
 From: Bob Rogers <rogers-perl6@rgrjr­.dyndns.org>
Date: Sat, 4 Oct 2008 22:08:10 -0400

From: "Patrick R. Michaud" <pmichaud@pobox.com­>
Date: Sat, 4 Oct 2008 18:15:57 -0500

. . .

All of the mechanisms I've been able to find in Parrot for
converting an arbitrary PMC to a number seem to result in
the code for infix:<*> that we have now. I'm open for
suggestions to improve this, though.

Pm

Hmm. My instinct would be to rely on MMD . . .

This exposes an MMD bug (it runs forever) . . .

Wrong; Parrot was replacing my Integer with the FixedPMCArray. (Grr.)
Here is an improvement:

.sub 'infix:*­' :multi(Perl6Array,_­)
.param pmc a
.param pmc b
$I0 = a
$P0 = new 'Integer'
$P0 = $I0
.return 'infix:*­'($P0, b)
.end

.sub 'infix:*­' :multi(_,Perl6Array­)
.param pmc a
.param pmc b
$I0 = b
$P0 = new 'Integer'
$P0 = $I0
.return 'infix:*­'(a, $P0)
.end

It works for some cases:

rogers@rgr> ../../perl6 -e 'my @a = <abc def ghi>; say @a * 483648;'
1450944
rogers@rgr> ../../perl6 -e 'my @a = <abc def ghi>; say 483648 * @a;'
1450944
rogers@rgr> ../../perl6 -e 'my @a = <abc def ghi>; say 483648 * 483648 * @a;'
701746163712
rogers@rgr> ../../perl6 -e 'my @a = <abc def ghi>; say 483648 * 483648 * 483648 * @a;'
339398128586981376
rogers@rgr>

But not others:

rogers@rgr> ../../perl6 -e 'my @a = <abc def ghi>; say @a * 2147483648;'
-6442450944
rogers@rgr> ../../perl6 -e 'my @a = <abc def ghi>; say 2147483648 * @a;'
get_bignum() not implemented in class 'Float'
current instr.: 'infix:*­' pc 16030 (src/gen_builtins.p­ir:10014)
. . .

-- Bob
Add comment
Mark Biggar 5 October 2008 08:37:29 permanent link ]
 Handling promotion (and demotion) between single and multi-precision
integers is fairly easy. And once you have that doing it for rationals
is basically free. Likewise promoting an Integer up to rational is
trivial and vice versa. But promotion (or demotion) between IEEE floats
and rationals is really hard and I don't know of a language that even
tries. The major problem is that the demotion from rational to IEEE
float is very lossy. In general, there are many possible distinct
rationals that convert into the same IEEE value and converting IEEE
float to the simplest rational out of that set is a very expensive
operation.. Once you're in rationals you probably never want to demote
back to IEEE (except possibly at the very end). Every language that
supports rationals, that I know of, leaves it up to the programmer to
decide whether they will be doing computations in IEEE float or
rationals and do not try to automatically convert back and forth. I
looked at thos and basically gave up when I was writing the perl 5
Bigint and Bigrat packages.

Before you discuss implementations, you should define exactly what rules
you are going to use for promotion and demotion between the various types.

--
Mark Biggar
Perl'sMaternal Uncle

mark@biggar.org
mark.a.biggar@conca­st.net


Add comment
Darren Duncan 5 October 2008 10:57:57 permanent link ]
 Mark Biggar wrote:
Handling promotion (and demotion) between single and multi-precision
integers is fairly easy. And once you have that doing it for rationals
is basically free. Likewise promoting an Integer up to rational is
trivial and vice versa. But promotion (or demotion) between IEEE floats
and rationals is really hard and I don't know of a language that even
tries. The major problem is that the demotion from rational to IEEE
float is very lossy. In general, there are many possible distinct
rationals that convert into the same IEEE value and converting IEEE
float to the simplest rational out of that set is a very expensive
operation.. Once you're in rationals you probably never want to demote
back to IEEE (except possibly at the very end). Every language that
supports rationals, that I know of, leaves it up to the programmer to
decide whether they will be doing computations in IEEE float or
rationals and do not try to automatically convert back and forth. I
looked at thos and basically gave up when I was writing the perl 5
Bigint and Bigrat packages.
Before you discuss implementations, you should define exactly what rules
you are going to use for promotion and demotion between the various types.

Since conversion from a rational to a IEEE float is almost always lossy, I
would say never do it automatically, and only do it when requested with an
explicit type cast, such as when converting a rational to an integer.

Generally speaking, IEEE floats are always in base 2 to a fixed precision,
so almost all math done with them is approximate; users pick IEEE floats
over unlimited rationals because they want to trade off precision for
resource efficiency.

If one receives input as an IEEE float and wants to do exact math with it
for some reason, they can convert it losslessly to a rational; this
conversion would also be done by explicit cast, not implicitly.

If the rational representation as a triple of integers I suggested is used,
then conversion from an IEEE float is inexpensive, and can go as follows.

Say the exact triple format looks like this:

subtype Int2_N of Int where { $^n >= 2 };

class Rational {
has Int $.mantissa = 0;
has Int2_N $.radix = 2;
has Int $.exponent = 0;
}

This format could represent a few sample numbers as follows:

0 -> 0*2**0
1 -> 1*2**0
1/8 -> 1*2**-3
0.001 -> 1*10**-3
3.14159 -> 314159*10**-5
4.5207196*10**30 -> 45207196*10**37
:2<101110.1101> -> :2<1011101101>*2**-­4
:16<DEADBEEF00> -> :16<DEADBEEF>*2**8

Now in a typical 64 bit IEEE float, if I'm not mistaken there are about 53
bits for a sign plus mantissa and those bits represent N*1/2+N*1/4+... sort
of like a 53 bit integer divided by 2**53; the 42 bit float then has 11
bits for a signed exponent, and a radix of 2 is implied.

So said IEEE float could be interpreted more or less as the number
determined by:

IEEEman*2**IEEEexp

... where IEEEman and IEEEexp are the conceptual values of those bit
patterns of the relevant parts of the IEEE float.

Then conversion into straight integers for my representation would be:

IEEEman*(2**53)*2**­(IEEEexp-53)

Something like that, or maybe slightly more complicated.

And so, any IEEE float would convert to a rational of the format I proposed
for essentially a constant amount of RAM usage regardless of what the IEEE
value is; RAM usage would not increase when IEEE floats with very large
numbers for exponents are converted, unlike a numerator/denominat­or
representation.

Now, doing math with rationals of the format I propose should cost roughly
the same as a numerator/denominat­or representation, but mine should use
less RAM in the extreme cases. Your speed profile would likely depend on
what normalization strategy you use. For example, if you normalize such
that the exponent is always -1 then your profile should be the same as a
numerator/denominat­or representation. By contrast, normalization for best
memory use would involve using as large a number as possible in the
exponent; ideally the radix would be small as possible, such as 2 or 10.

-- Darren Duncan
Add comment
Darren Duncan 5 October 2008 11:08:26 permanent link ]
 Darren Duncan wrote:
4.5207196*10**30 -> 45207196*10**37

Before anyone nitpicks, I meant to say on that line:

4.5207196*10**44 -> 45207196*10**37

-- Darren Duncan
Add comment
Michael G Schwern 5 October 2008 17:49:17 permanent link ]
 Darren Duncan wrote:
Patrick R. Michaud wrote:
Correct. I suspect that eventually the Rakudo developers will have
to develop a custom set of PMCs for Perl 6 behaviors rather than
relying on the Parrot ones.
I think it would be better for things like unlimited-precision­ integers
and rationals to be Parrot generic PMCs rather than Perl 6 specific
ones, since there are other languages that also have unlimited-precision­
numbers (for example Python afaik) and it would be better to have a
common implementation. Several popular languages have unlimiteds now,
and more are coming over time.

+1

The basics of sane numbers should be pushed down into Parrot.
(Of course, my vote counts for bupkis as I'm not going to be the one to
implement it)


--
Whip me, beat me, make my code compatible with VMS!
Add comment
TSa 5 October 2008 20:06:46 permanent link ]
 HaloO,

On Sunday, 5. October 2008 04:23:42 Darren Duncan wrote:
Note that just as integers are naturally radix independent, the unlimited
rationals should be too, and the latter can compactly represent all
rationals as a triple of integers corresponding roughly to a (normalized)
[mantissa, radix, exponent] triple; with that approach you also get
unlimited floats for free, so no reason to make floats an exception where
they aren't unlimited where integers and other rationals are; after all,
what is a float or scientific notation than just another notation for a
rational value literal.

I want to stress this last point. We have the three types Int, Rat and Num.
What exactly is the purpose of Num? The IEEE formats will be handled
by num64 and the like. Is it just there for holding properties? Or does
it do some more advanced numeric stuff?

Another matter is how to represent irrationals. With IEEE floats which are
basically non-uniformly spaced integers imprecession is involved anyway.
But sqrt(2) is a ratio of two infinite integers. How is that handled? Here
I see a way for Num to shine as a type that also involves lazy approximations.
But then we need a way for the programmer to specify how these approximations
shall be handled.


Regards, TSa.
--
"The unavoidable price of reliability is simplicity" -- C.A.R. Hoare
"Simplicity does not precede complexity, but follows it." -- A.J. Perlis
1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Add comment
Doug McNutt 5 October 2008 20:38:34 permanent link ]
 On Sunday, 5. October 2008 04:23:42 Darren Duncan wrote:
Note that just as integers are naturally radix independent, the unlimited
rationals should be too, and the latter can compactly represent all
rationals as a triple of integers corresponding roughly to a (normalized)
[mantissa, radix, exponent] triple; with that approach you also get
unlimited floats for free, so no reason to make floats an exception where
they aren't unlimited where integers and other rationals are; after all,
what is a float or scientific notation than just another notation for a
rational value literal.
At 18:06 +0200 10/5/08, TSa (Thomas Sandla ) wrote:
I want to stress this last point. We have the three types Int, Rat and Num.
What exactly is the purpose of Num? The IEEE formats will be handled
by num64 and the like. Is it just there for holding properties? Or does
it do some more advanced numeric stuff?
Another matter is how to represent irrationals. With IEEE floats which are
basically non-uniformly spaced integers imprecession is involved anyway.
But sqrt(2) is a ratio of two infinite integers. How is that handled? Here
I see a way for Num to shine as a type that also involves lazy approximations.
But then we need a way for the programmer to specify how these approximations
shall be handled.

I'm not so sure that sophisticated numbering is necessary for a practical extraction and report language. But. . .

Symbolic algebra packages handle irrationals like sqrt(2) with a "root of" function which can be included in a result before it is deliberately converted to an approximation in a later step. Perl should NOT do things like that.

As for unlimited precision in floats I'd rather see a floating point number triple that includes, in its structure, an estimate of error, and physical units.

Multiplying amperes by volts would then return watts with an appropriately calculated estimate of the error. Testing for zero would include the error estimate.

When I work with data from the power company expressed in MMBTU I can add to a working table of units that MMBTU translates to 10^6 BTU because the M means 1000 as in millia pasuum. I could also provide a conversion from BTU to joules and have it properly handled.

Many arithmetic errors are the result of not keeping the units inside of the evaluation. The result is newspaper articles that confuse energy and power as they extract from data provided by power company engineers. "1 kW per day" is meaningless. I wonder if they use perl to extract the data.

And what are those two infinite integers? I wonder if there is a series that expresses each one?

--

--> A fair tax is one that you pay but I don't <--
Add comment
Michael G Schwern 5 October 2008 21:42:13 permanent link ]
 TSa (Thomas Sandla ) wrote:
I want to stress this last point. We have the three types Int, Rat and Num.
What exactly is the purpose of Num? The IEEE formats will be handled
by num64 and the like. Is it just there for holding properties? Or does
it do some more advanced numeric stuff?

"Int", "Rat" [1] and "Num" are all human types. They work like humans were
taught numbers work in math class. They have no size limits. They shouldn't
lose accuracy. [2]

As soon as you imply that numbers have a size limit or lose accuracy you are
thinking like a computer. That's why "num64" is not a replacement for "Num",
conceptually nor is "int64" a replacement for "Int". They have limits and
lose accuracy.

Making "Num" just work like humans expect is the "more advanced numeric stuff"
I suppose. :)­


[1] As a name "Rat" as the type which holds fractions is about as good
as "Float" to be the type which holds decimal numbers. Gotta be
something that makes more sense to non CS people. Like, say, "Fraction".

[2] "Num" should have an optional limit on the number of decimal places
it remembers, like NUMERIC in SQL, but that's a simple truncation.


--
184. When operating a military vehicle I may *not* attempt something
"I saw in a cartoon".
-- The 213 Things Skippy Is No Longer Allowed To Do In The U.S. Army
http://skippyslist.­com/list/
Add comment
Nicholas Clark 5 October 2008 22:23:52 permanent link ]
 On Sat, Oct 04, 2008 at 09:37:29PM -0700, Mark Biggar wrote:

trivial and vice versa. But promotion (or demotion) between IEEE floats
and rationals is really hard and I don't know of a language that even
tries. The major problem is that the demotion from rational to IEEE
float is very lossy. In general, there are many possible distinct
rationals that convert into the same IEEE value and converting IEEE
float to the simplest rational out of that set is a very expensive
operation.. Once you're in rationals you probably never want to demote

And I can't see why it's anything other than a heuristic. For example,
0.2 is an infinite binary fraction. So store that as an IEEE float (heck,
in any form of float with a binary mantissa of fixed precision) and 1/5 isn't
the *only* rational that could have got you there. Something like

0b00011001100110011­00110011001100110011­0011001100110011 /
0b10000000000000000­00000000000000000000­0000000000000000

(900719925474099 / 4503599627370496)

would also result in the same bit pattern in the mantissa.

How does the implementation tell which rational the floating point value
actually came from

back to IEEE (except possibly at the very end). Every language that
supports rationals, that I know of, leaves it up to the programmer to
decide whether they will be doing computations in IEEE float or
rationals and do not try to automatically convert back and forth. I
looked at thos and basically gave up when I was writing the perl 5
Bigint and Bigrat packages.
Before you discuss implementations, you should define exactly what rules
you are going to use for promotion and demotion between the various types.

Studiously ignoring that request to nail down promotion and demotion, I'm
going to jump straight to implementation, and ask:

If one has floating point in the mix [and however much one uses rationals,
and has the parser store all decimal string constants as rationals, floating
point enters the mix as soon as someone wants to use transcendental functions
such as sin(), exp() or sqrt()], I can't see how any implementation that wants
to preserve "infinite" precision for as long as possible is going to work,
apart from

storing every value as a thunk that holds the sequence of operations that
were used to compute the value, and defer calculation for as long as
possible. (And possibly as a sop to efficiency, cache the floating point
outcome of evaluating the thunk if it gets called)


Nicholas Clark
Add comment
Tom Christiansen 6 October 2008 05:29:31 permanent link ]
 In-Reply-To: Message from Nicholas Clark <nick@ccl4.org>
of "Sun, 05 Oct 2008 22:13:14 BST." <20081005211314.GA6­160@plum.flirble.org­>

Studiously ignoring that request to nail down promotion and demotion, I'm
going to jump straight to implementation, and ask:

If one has floating point in the mix [and however much one uses rationals,
and has the parser store all decimal string constants as rationals, floating
point enters the mix as soon as someone wants to use transcendental functions
such as sin(), exp() or sqrt()], I can't see how any implementation that wants
to preserve "infinite" precision for as long as possible is going to work,
apart from

storing every value as a thunk that holds the sequence of operations that
were used to compute the value, and defer calculation for as long as
possible. (And possibly as a sop to efficiency, cache the floating point
outcome of evaluating the thunk if it gets called)

Nicholas Clark

My dear Nicholas,

You mentioned sin(), exp(), and sqrt() as being "transcendental" functions,
but this is not true! Perhaps you meant something more in the way of their
being--um, "irrational". but far be it from me to risk using so loaded a
word in reference to anyone's hypothetical intentions or rationale! :-)­

While all transcendentals are indeed irrationals, the opposite relationship
does *not* apply. It's all really rather simple, provided you look at it
as a brief, binary decision-tree.

=> All reals are also one of either rational or irrational:

+ Rational numbers are those expressible as the RATIO of I/J,
where I is any integer and J any non-zero integer.

- Irrationals are all other reals *EXCEPT* the rationals.

=> All irrationals are also one of either algebraic or transcendental:

+ Algebraic numbers are solutions to polynomial equations of a single
variable and integer coefficients. When you solve for x in the
polynomial equation 3*x**2 - 15 == 0, you get an algebraic number.

- Transcendentals are all other irrationals *EXCEPT* the algebraics.

Thinking of the sine function and its inverse, I notice that
sin(pi/2) == 1 and asin(1) is pi/2. Pi is *the* most famous
of transcendental numbers, and sin() is a transcendental function.

Thinking of the exponential function and its inverse, I notice that
exp(1) == e and log(e) == 1. And e, "Euler's number", is likely the
#2 most famous transcendental, and exp() is a transcendental function.

However, we come now to a problem.

If you solved the simple equation I presented above as one whose solution
was by definition *not* a transcendental but rather an algebraic number,
you may have noticed that solution is 5**(1/2), better known as sqrt(5).
So that makes sqrt(5) an algebraic number, and sqrt() is an algebraic
function, which means therefore that it is *not* a transcendental one.

Q.E.D. :-)­

Ok, I was teasing a little. But I'd now like to politely and sincerely
inquire into your assertion that floating point need inevitably enter the
picture just to determine sin(x), exp(x), or sqrt(x).

Your last one, sqrt(), isn't hard at all. Though I no longer recall the
algorithm, there exists one for solving square roots by hand that is only a
little more complicated than that of solving "long division" by hand. Like
division, it is an iterative process, somewhat tedious but quite well-defined
easily implemented even on pen and paper. Perhaps that has something to do
with sqrt() being an algebraic function. :-)­ j/k

As for the two transcendental functions, this does ask for more work. But
it's not as though we do not understand them, nor how to derive them at
need from first principles! They aren't magic black-ball functions with
secret look-up tables that when poked with a given input, return some
arbitrary answer.

We *know* how to *do* these!

Sure, many and probably most solutions, at least for the transendentals, do
involve power series, and usually Taylor Series. But this only means that
you get to joyfully sum up an infinite sequence of figures receding into
infinity ("And beyond!" quoth Buzz), but where each figure in said series
tends to be a reasonably simple and straightforward computation.

For example, each term in the Taylor Series for exp(x) is simply x**N / N!,
and the final answer the sum of all suchterms for N going from 0 to infinity.
Its series is therefore

x**0 / 0! # er: that's just 1, of course :-)­
+ x**1 / 1!
+ x**2 / 2!
+ x**3 / 3!
+ x**4 / 4!
+
+ + + + + + + + + + ad infinitum.

For sin(x), it's a bit harder, but not much: the series is a convergent one
of alternating sign, running N from 0 to infinity and producing a series
that looks like this:

(x**1 / 1!) # er: that's just x, of course :-)­
- (x**3 / 3!)
+ (x**5 / 5!)
- (x**7 / 7!)
+ (x**9 / 9!)
-
+ - + - + - + - + ad infinitum.

Each term in the sin(x) series is still a comparitively easy one,
reading much better on paper than on the computer with lazy ASCII
equations, for I assume you'd be subkeen on eqn(1) descriptions. :)­

( (-1)**N * (x ** (2*N - 1)) )
/
(2*N + 1)!

where that's a factorial bang, not an exclamatory one. :-)­

Now you're very nearly done: all you have left to do to get that perfect
answer is add up infinitely many individual terms, for the limit of that
summed-up infinite series is none other than the *exact* answer to those
transcendental functions. They don't have algebraic solutions, but they
do have algorithmic ones, and this is not rocket science. On the other
hand, you probably can't even *do* rocket science without such nifty
mathematical devices. :-)­

Nick, you and I both know the secret of infinity, although your average
pedestrian--call him Zeno--will surely falter in its pursuit. And that
secret is that infinity means nothing fancier than "as many as I jolly well
please, thank you very much". In other words, you just keep going (and
going (and going)), until finally you arrive at however many digits of
precision you've been asked to produce.

Now, just where in those equations I've presented above do you see some
need for and need to resort to lossy floating-point numbers? I don't see
any. Sure, I do see plenty of places for Memoize-style caching of these
numbers of infinite (read: arbitrarily great) precision.

But where is the need floating-point that you seem to see, and why?

Beyong the rockety equations I just presented above, I also have to offer
you not just one, but *two* existence-proofs that you've no need to resort
to machine-native floating-point variables or instructions.

The first is bc(1). It reports that the square root of 5 played
out to to 300 digits of precision is:

$ (echo scale=300; echo 'sqrt(5)') | bc -l
2.23606797749978969­64091736687312762354­40618359611525724270­8972454105\
2092563780489941441­44083787822749695081­76150773783504253267­7244470738\
6358636012153345270­88667781731918791658­11276645322639856580­5357613504\
1753378500342339241­40644420864325390972­52592627228876299517­4024406816\
1177590890949849237­1390729

Here are 50 digits of precision for sin(1):

$ (echo scale=50; echo 's(1)') | bc -l
.841470984807896506­65250232163029899962­256306079837

And here are 500 digits for exp(1)

$ (echo scale=500; echo 'e(1)') | bc -l
2.71828182845904523­53602874713526624977­57247093699959574966­9676277240\
7663035354759457138­21785251664274274663­91932003059921817413­5966290435\
7290033429526059563­07381323286279434907­63233829880753195251­0190115738\
3418793070215408914­99348841675092447614­60668082264800168477­4118537423\
4544243710753907774­49920695517027618386­06261331384583000752­0449338265\
6029760673711320070­93287091274437470472­30696977209310141692­8368190255\
1510865746377211125­23897844250569536967­70785449969967946864­4549059879\
3163688923009879312­

So, that's one existence proof.

And if you look at Math::BigFloat, you'll fine the other.
Or bignum, if you prefer.


% perl -Mbignum=p,-305 -E 'say sqrt(5)'
2.23606797749978969­64091736687312762354­40618359611525724270­89724541052092563780­48994144144083787822­74969508176150773783­50425326772444707386­35863601215334527088­66778173191879165811­27664532263985658053­57613504175337850034­23392414064442086432­53909725259262722887­62995174024406816117­75908909498492371390­72972890

or formatted the way bc does it:

2.23606797749978969­64091736687312762354­40618359611525724270­8972454105\
2092563780489941441­44083787822749695081­76150773783504253267­7244470738\
6358636012153345270­88667781731918791658­11276645322639856580­5357613504\
1753378500342339241­40644420864325390972­52592627228876299517­4024406816\
1177590890949849237­139072972890

And sin(1) to a ways out:

% perl -Mbignum=p,-55 -E 'say sin(1)'
0.84147098480789650­66525023216302989996­225630607983710657

Followed by a good 500+ digits of e, with formatting:

% perl -Mbignum=p,-505 -E 'say exp(1)'

2.71828182845904523­53602874713526624977­57247093699959574966­9676277240\
7663035354759457138­21785251664274274663­91932003059921817413­5966290435\
7290033429526059563­07381323286279434907­63233829880753195251­0190115738\
3418793070215408914­99348841675092447614­60668082264800168477­4118537423\
4544243710753907774­49920695517027618386­06261331384583000752­0449338265\
6029760673711320070­93287091274437470472­30696977209310141692­8368190255\
1510865746377211125­23897844250569536967­70785449969967946864­4549059879\
3163688923009879312­77362

So, um, what's that floating-point thing about again, eh? :-)­

--tom
Add comment
Darren Duncan 6 October 2008 07:37:00 permanent link ]
 Doug McNutt wrote:
At 18:06 +0200 10/5/08, TSa (Thomas Sandla ) wrote:
Another matter is how to represent irrationals. With IEEE floats which are
basically non-uniformly spaced integers imprecession is involved anyway.
But sqrt(2) is a ratio of two infinite integers. How is that handled?

I would not consider an irrational to be a ratio of anything; rather it is
a number that can't be expressed as a ratio of 2 integers.

Symbolic algebra packages handle irrationals like sqrt(2) with a "root
of" function which can be included in a result before it is deliberately
converted to an approximation in a later step. Perl should NOT do things
like that.

Whether or not Perl has built-in support for symbolic math, something which
incidentally some other general purpose languages do have afaik, any Perl
representations of exact irrational numbers definitely should be symbolic
in nature, that is an irrational number value is simply defined by a
formula involving operators and rational literals, and any type
implementing this would be neither the Int nor Rat type.

As for unlimited precision in floats I'd rather see a floating point
number triple that includes, in its structure, an estimate of error, and
physical units.

I see that you can have both unlimited precision rationals (which is what
floats are) that also know the error estimate and physical units; they
would be defined in terms of an exact precision rational plus the estimate
and units as additional attributes or metadata.

-- Darren Duncan
Add comment


Darren Duncan 6 October 2008 08:28:58 permanent link ]
 Michael G Schwern wrote:
TSa (Thomas Sandla ) wrote:
I want to stress this last point. We have the three types Int, Rat and Num.
What exactly is the purpose of Num? The IEEE formats will be handled
by num64 and the like. Is it just there for holding properties? Or does
it do some more advanced numeric stuff?
"Int", "Rat" [1] and "Num" are all human types. They work like humans were
taught numbers work in math class. They have no size limits. They shouldn't
lose accuracy. [2]
As soon as you imply that numbers have a size limit or lose accuracy you are
thinking like a computer. That's why "num64" is not a replacement for "Num",
conceptually nor is "int64" a replacement for "Int". They have limits and
lose accuracy.

All agreed.

[2] "Num" should have an optional limit on the number of decimal places
it remembers, like NUMERIC in SQL, but that's a simple truncation.

I disagree.

For starters, any "limit" built into a type definition should be defined not as
stated above but rather with a simple subtype declaration, eg "subtype of Rat
where ..." that tests for example that the Rat is an exact multiple of 1/1000.

Second, any truncation should be done at the operator level not at the type
level; for example, the rational division operator could have an optional extra
argument that says the result must be rounded to be an exact multiple of 1/1000;
without the extra argument, the division doesn't truncate anything.

Any numeric operations that would return an irrational number in the general
case, such as sqrt() and sin(), and the user desires the result to be truncated
to an exact rational number rather than as a symbolic number, then those
operators should have an extra argument that specifies rounding, eg to an exact
multiple of 1/1000.

Note, a generic numeric rounding operator would also take the "exact multiple
of" argument rather than a "number of digits" argument, except when that
operator is simply rounding to an integer, in which case no such argument is
applicable.

Note, for extra determinism and flexibility, any operation rounding/truncating­
to a rational would also take an optional argument specifying the rounding
method, eg so users can choose between the likes of half-up, to-even, to-zero,
etc. Then Perl can easily copy any semantics a user desires, including when
code is ported from other languages and wants to maintain exact semantics.

Now, as I see it, if "Num" has any purpose apart from "Rat", it would be like a
"whatever" numeric type or effectively a union of the
Int|Rat|that-symbol­ic-number-type|etc types, for people that just want to accept
numbers from somewhere and don't care about the exact semantics. The actual
underlying type used in any given situation would determine the exact semantics.
So Int and Rat would be exact and unlimited precision, and maybe Symbolic or
IRat or something would be the symbolic number type, also with exact precision
components.

Come to think of it, isn't "whatever" how Num is already defined? If so I think
that is clearly distinct from Rat.

-- Darren Duncan

Add comment
Darren Duncan 6 October 2008 08:34:29 permanent link ]
 Nicholas Clark wrote:
If one has floating point in the mix [and however much one uses rationals,
and has the parser store all decimal string constants as rationals, floating
point enters the mix as soon as someone wants to use transcendental functions
such as sin(), exp() or sqrt()], I can't see how any implementation that wants
to preserve "infinite" precision for as long as possible is going to work,
apart from
storing every value as a thunk that holds the sequence of operations that
were used to compute the value, and defer calculation for as long as
possible. (And possibly as a sop to efficiency, cache the floating point
outcome of evaluating the thunk if it gets called)

Floating point has no effect on this. A float is just a syntax for an exact
rational. What you're talking about mostly is how an exact irrational would be
represented, symbolically. The result of an exact numeric sin() etc would be a
symbolic number, and it is only when you separately explicitly convert it to a
rational does any rounding and loss occur, and it would be the rounding
operation itself that has extra parameters to control the rounding.
Alternately, an inexact numeric sin() that results in an exact rational is just
a wrapper over the last 2 operations combined, and it takes rounding-control
parameters. I see no problem here. -- Darren Duncan
Add comment


Michael G Schwern 6 October 2008 10:20:22 permanent link ]
 So, the concrete use-case I'm thinking of here is currency.


Darren Duncan wrote:
[2] "Num" should have an optional limit on the number of decimal places
it remembers, like NUMERIC in SQL, but that's a simple truncation.
I disagree.
For starters, any "limit" built into a type definition should be defined
not as stated above but rather with a simple subtype declaration, eg
"subtype of Rat where ..." that tests for example that the Rat is an
exact multiple of 1/1000.
Second, any truncation should be done at the operator level not at the
type level; for example, the rational division operator could have an
optional extra argument that says the result must be rounded to be an
exact multiple of 1/1000; without the extra argument, the division
doesn't truncate anything.
Any numeric operations that would return an irrational number in the
general case, such as sqrt() and sin(), and the user desires the result
to be truncated to an exact rational number rather than as a symbolic
number, then those operators should have an extra argument that
specifies rounding, eg to an exact multiple of 1/1000.

That seems like scattering a lot of redundant extra arguments around. The
nice thing about doing it as part of the type is you just specify it once.

But instead of truncating data in the type, maybe what I want is to leave the
full accuracy inside and instead override string/numification­ to display only
2 decimal places.

But sometimes I want to hang onto fractional pennies and use them in
calculation, just hide them from view. And sometimes I don't.


Note, a generic numeric rounding operator would also take the "exact
multiple of" argument rather than a "number of digits" argument, except
when that operator is simply rounding to an integer, in which case no
such argument is applicable.
Note, for extra determinism and flexibility, any operation
rounding/truncating­ to a rational would also take an optional argument
specifying the rounding method, eg so users can choose between the likes
of half-up, to-even, to-zero, etc. Then Perl can easily copy any
semantics a user desires, including when code is ported from other
languages and wants to maintain exact semantics.

Yes, this is very important for currency operations.


Now, as I see it, if "Num" has any purpose apart from "Rat", it would be
like a "whatever" numeric type or effectively a union of the
Int|Rat|that-symbol­ic-number-type|etc types, for people that just want
to accept numbers from somewhere and don't care about the exact
semantics. The actual underlying type used in any given situation would
determine the exact semantics. So Int and Rat would be exact and
unlimited precision, and maybe Symbolic or IRat or something would be
the symbolic number type, also with exact precision components.

That sounds right. It's the "whatever can conceivably be called a number" type.



--
44. I am not the atheist chaplain.
-- The 213 Things Skippy Is No Longer Allowed To Do In The U.S. Army
http://skippyslist.­com/list/
Add comment
Tom Christiansen 21 October 2008 03:54:29 permanent link ]
 On Mon, 06 Oct 2008 at wee small hour of 02:20:22 EDT
you, Michael G Schwern <schwern@pobox.com>­, wrote:

Darren Duncan wrote:

[2] "Num" should have an optional limit on the number of
decimal places it remembers, like NUMERIC in SQL, but
that's a simple truncation.

I disagree.

Any numeric operations that would return an irrational number
in the general case, such as sqrt() and sin(), and the user
desires the result to be truncated to an exact rational number
rather than as a symbolic number, then those operators should
have an extra argument that specifies rounding, eg to an exact
multiple of 1/1000.

That seems like scattering a lot of redundant extra arguments
around. The nice thing about doing it as part of the type is
you just specify it once.

But instead of truncating data in the type, maybe what I want
is to leave the full accuracy inside and instead override
string/numification­ to display only 2 decimal places.

This is currently something of an annoyance with Math::Complex.
It needs a way of specify epsilon.

If you ask for both sqrt()s of 4, you get

(2, -2+2.44929359829471­e-16i)

in Cartesian but in Polar:

( [2,0], [2,pi] )

Is the problem that it's working in Polar and the conversion to
Cartesian is off by a wee bit? I would really like to get
Cartesian answers of (2, -2), not that -2e-16i silliness.

If you ask for both roots of -4, you get

Cartesian:
( 1.22464679914735e-1­6+2i, -3.67394039744206e-­16-2i )
Polar:
( [2,pi/2], [2,-1pi/2] );

But I'd like a Cartesian return of (2i, -2i).
And a Polar return of ([2,pi/2],[2,-pi/2]).

It's worse still with the 10 roots of 2**10:

The 10 roots of 1024 are:
CRTSN: 1: 2
POLAR: 1: [2,0]
CRTSN: 2: 1.61803398874989+1.­17557050458495i
POLAR: 2: [2,pi/5]
CRTSN: 3: 0.618033988749895+1­.90211303259031i
POLAR: 3: [2,2pi/5]
CRTSN: 4: -0.618033988749895+­1.90211303259031i
POLAR: 4: [2,3pi/5]
CRTSN: 5: -1.61803398874989+1­.17557050458495i
POLAR: 5: [2,4pi/5]
CRTSN: 6: -2+2.44929359829471­e-16i
POLAR: 6: [2,pi]
CRTSN: 7: -1.61803398874989-1­.17557050458495i
POLAR: 7: [2,-4pi/5]
CRTSN: 8: -0.618033988749895-­1.90211303259031i
POLAR: 8: [2,-3pi/5]
CRTSN: 9: 0.618033988749894-1­.90211303259031i
POLAR: 9: [2,-2pi/5]
CRTSN: 10: 1.61803398874989-1.­17557050458495i
POLAR: 10: [2,-1pi/5]

The 10 roots of -1024 are:
CRTSN: 1: 1.90211303259031+0.­618033988749895i
POLAR: 1: [2,0.314159265358979]
CRTSN: 2: 1.17557050458495+1.­61803398874989i
POLAR: 2: [2,0.942477796076938]
CRTSN: 3: 1.22464679914735e-1­6+2i
POLAR: 3: [2,pi/2]
CRTSN: 4: -1.17557050458495+1­.61803398874989i
POLAR: 4: [2,2.19911485751286]
CRTSN: 5: -1.90211303259031+0­.618033988749895i
POLAR: 5: [2,2.82743338823081]
CRTSN: 6: -1.90211303259031-0­.618033988749895i
POLAR: 6: [2,-2.82743338823081]
CRTSN: 7: -1.17557050458495-1­.61803398874989i
POLAR: 7: [2,-2.19911485751286]
CRTSN: 8: -3.67394039744206e-­16-2i
POLAR: 8: [2,-1pi/2]
CRTSN: 9: 1.17557050458495-1.­6180339887499i
POLAR: 9: [2,-0.942477796076938]
CRTSN: 10: 1.90211303259031-0.­618033988749895i
POLAR: 10: [2,-0.31415926535898]

Note, a generic numeric rounding operator would also take the
"exact multiple of" argument rather than a "number of digits"
argument, except when that operator is simply rounding to an
integer, in which case no such argument is applicable.

Note, for extra determinism and flexibility, any operation
rounding/truncating­ to a rational would also take an optional
argument specifying the rounding method, eg so users can
choose between the likes of half-up, to-even, to-zero, etc.
Then Perl can easily copy any semantics a user desires,
including when code is ported from other languages and wants
to maintain exact semantics.

Yes, this is very important for currency operations.

Now, as I see it, if "Num" has any purpose apart from "Rat",
it would be like a "whatever" numeric type or effectively a
union of the Int|Rat|that-symbol­ic-number-type|etc types, for
people that just want to accept numbers from somewhere and
don't care about the exact semantics. The actual underlying
type used in any given situation would determine the exact
semantics. So Int and Rat would be exact and unlimited
precision, and maybe Symbolic or IRat or something would be
the symbolic number type, also with exact precision
components.

That sounds right. It's the "whatever can conceivably be
called a number" type.

I think you might be surprised by what some people conceive
of by numbers. :-(­

--tom

#!/usr/bin/perl

use strict;
use warnings;

use Math::Complex;

my $STYLE = "NORMAL";
# my $STYLE = "HACKED";

unless (@ARGV) {
die "usage: $0 number rootcount\n";
}

my