On Mon, 06 Oct 2008 at wee small hour of 02:20:22 EDT you, Michael G Schwern <[EMAIL PROTECTED]>, 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.44929359829471e-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-16+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.44929359829471e-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-16+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-symbolic-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 ($number, $rootcount) = @ARGV; $number = cplx($number); die "$0: $number poor for rooting\n" if !$number; die "$0: $rootcount should be positive integer" if $rootcount && int($rootcount) != $rootcount; print "The $rootcount roots of $number are:\n"; my @roots = root($number, int($rootcount)); my $width = length @roots; for (my $idx = 0; $idx < @roots; $idx++) { my $z = $roots[$idx]; my $r = Re($z); my $i = Im($z); if ($STYLE eq "NORMAL") { printf "CRTSN: %${width}d: %s\n", 1+$idx, $z; $z->display_format("polar"); printf "POLAR: %${width}d: %s\n", 1+$idx, $z; next; } printf "%${width}d: ", 1+$idx; if ($r) { my $s = sprintf "%.6f", $r; $s =~ s/0+$//; if ($s =~ s/\.$//) { # whole RE part print (($s < 0) ? "-" : " "); printf "%-7d", abs($s); } else { printf "%8g", $s; } } else { } if ($i) { my $s = sprintf "%.6f", $i; $s =~ s/0+$//; $s =~ s/\.$//; if ($s ne '0') { print " " if $s !~ m/\./; print (($s < 0) ? " -" : "+" ); if ($s !~ m/\./) { printf "%di", abs($s); } else { printf "%7gi", abs($s); } } } print "\n\n"; }