Modified:
docs/Perl6/Spec/S02-bits.pod
docs/Perl6/Spec/S09-data.pod
Log:
[S02,S09] more tweakage of rat semantics
Rat types are instantiations of a Rational role as suggested by moritz_++
Modified: docs/Perl6/Spec/S02-bits.pod
===================================================================
--- docs/Perl6/Spec/S02-bits.pod 2009-11-17 23:59:27 UTC (rev 29120)
+++ docs/Perl6/Spec/S02-bits.pod 2009-11-18 00:53:40 UTC (rev 29121)
@@ -629,12 +629,15 @@
are generally not used directly as object types. For instance
all the numeric types perform the C<Numeric> role, and all
string types perform the C<Stringy> role, but there's no
-such thing as a "Numeric" object. Common roles include:
+such thing as a "Numeric" object, since these are generic
+types that must be instantiated with extra arguments to produce
+normal object types. Common roles include:
Stringy
Numeric
Real
Integral
+ Rational
Callable
Positional
Associative
@@ -654,7 +657,7 @@
but by default it is the same type as a native C<num>. See below.
C<Rat> supports extended precision rational arithmetic.
-Dividing two C<Int> objects using C<< infix:</> >> produces a
+Dividing two C<Integral> objects using C<< infix:</> >> produces a
a C<Rat>, which is generally usable anywhere a C<Num> is usable, but
may also be explicitly cast to C<Num>. (Also, if either side is
C<Num> already, C<< infix:</> >> gives you a C<Num> instead of a C<Rat>.)
@@ -673,7 +676,8 @@
However, for pragmatic reasons, C<Rat> values are guaranteed to be
exact only up to a certain point. By default, this is the precision
-that would be represented by the C<Rat64> type, which has a numerator
+that would be represented by the C<Rat64> type, which is an alias for
+C<Rational[Int,int64]>, which has a numerator
of C<Int> but is limited to a denominator of C<int64>. A C<Rat64> that
would require more than 64 bits of storage in the denominator is
automatically converted either to a C<Num> or to a lesser-precision
@@ -681,21 +685,36 @@
as C<rat64> limit the size of both numerator and denominator, though
not to the same size. The numerator should in general be twice the
size of the denominator to support user expectations. For instance,
-a C<rat8> should actually support C<int16/int8>, allowing
+a C<rat8> actually supports C<Rational[int16,int8], allowing
numbers like C<100.01> to be represented, and a C<rat64>,
-defined as C<int128/int64>, can hold the number of seconds since
-the Big Bang with picosecond precision. Though perhaps not with
-picosecond accuracy...)
+defined as C<Rational[int128,int64]>, can hold the number of seconds since
+the Big Bang with attosecond precision. Though perhaps not with
+attosecond accuracy...)
For applications that really need arbitrary precision denominators as
-well as numerators at the cost of performance, C<Ratio> may be used,
-which is stored as C<Int/Int>, that is, as arbitrary precision in
-both parts. There is no literal form for a C<Ratio>, so it must
-be constructed using C<Ratio.new($nu,$de)>. In general, only math
-operators with at least one C<Ratio> argument will return another
-C<Ratio>, to prevent accidental promotion of reasonably fast C<Rat>
-values into arbitrarily slow C<Ratio> values.
+well as numerators at the cost of performance, C<FatRat> may be used,
+which is defined as C<Rational[Int,Int], that is, as arbitrary precision in
+both parts. There is no literal form for a C<FatRat>, so it must
+be constructed using C<FatRat.new($nu,$de)>. In general, only math
+operators with at least one C<FatRat> argument will return another
+C<FatRat>, to prevent accidental promotion of reasonably fast C<Rat>
+values into arbitrarily slow C<FatRat> values.
+Although most rational implementations normalize or "reduce" fractions
+to their smallest representation immediately through a gcd algorithm,
+Perl allows a rational datatype to do so lazily at need, such as
+whenever the denominator would run out of precision, but avoid the
+overhead otherwise. Hence, if you are adding a bunch of C<Rat>s that
+represent, say, dollars and cents, the denominator may stay 100 the
+entire way through. The C<.nu> and C<.de> methods will return these
+unreduced values. You can use C<$rat.=norm> to normalize the fraction.
+The C<.perl> method will produce a decimal number if the denominator is
+a multiple of 10. Otherwise it will normalize and return a rational
+literal of the form -47/3. Stringifying a rational always converts
+to C<Num> and stringifies that, so the rational internal form is
+somewhat hidden from the casual user, who would generally prefer
+to see decimal notation.
+
=item *
Perl 6 should by default make standard IEEE floating point concepts
@@ -1091,7 +1110,7 @@
Int Perl integer (allows Inf/NaN, arbitrary precision, etc.)
Num Perl number (approximate Real, generally via floating point)
Rat Perl rational (exact Real, limited denominator)
- Ratio Perl rational (unlimited precision in both parts)
+ FatRat Perl rational (unlimited precision in both parts)
Complex Perl complex number
Bool Perl boolean
Exception Perl exception
@@ -1142,11 +1161,11 @@
Class Roles
===== =====
Str Stringy
- Bit Numeric Boolean
+ Bit Numeric Boolean Integral
Int Numeric Integral
Num Numeric Real
- Rat Numeric Real
- Ratio Numeric Real
+ Rat Numeric Real Rational
+ FatRat Numeric Real Rational
Complex Numeric
Bool Boolean
Exception Failure
Modified: docs/Perl6/Spec/S09-data.pod
===================================================================
--- docs/Perl6/Spec/S09-data.pod 2009-11-17 23:59:27 UTC (rev 29120)
+++ docs/Perl6/Spec/S09-data.pod 2009-11-18 00:53:40 UTC (rev 29121)
@@ -81,9 +81,11 @@
run-time system (presumably Parrot) is compiled in. So C<int>
typically means C<int32> or C<int64>, while C<num> usually means
C<num64>, and C<complex> means two of whatever C<num> turns out to be.
-For symmetry around the decimal point, native rats have a numerator
-that is twice the size of their denominator, such that a rat32 actually
-has an int64 for its numerator.
+For symmetry around the decimal point, native C<rat>s have a numerator
+that is twice the size of their denominator, such that a C<rat32> actually
+has an C<int64> for its numerator. Custom rational types may
+be created by instantiating the C<Rational> role with two types;
+if both types used are native types, the resulting type is considered a native type.
You are, of course, free to use macros or type declarations to
associate additional names, such as "short" or "single". These are
Wouldn't it be better to produce a decimal number if the denominator
equals of 2**n * 5**m for n,m unsigned int? Before displaying the
value should be "decimal-normalized" by multiplying numerator and
denominator by 2**|n-m| or 5**|n-m| depending on sign(n-m).
Otherwise adding Rats representing dollars and cents which are
immediately normalized could produce flapping between rational literal
form and decimal number form.
Aside from that the specification should be: if the denominator equals
10**n, with n unsigned integer, .perl will produce a decimal number.
Otherwise 1/30 would produce a decimal number like 0.0333333..., which
was probably not intended.
Regards,
Ron
Good catch; I thought "power" and typed "multiple".
I was hesitating to extend it to require factoring for the solution,
but there's actually a fast way to factor for 2's and 5's. Just shift
off all the 0 bits on the bottom to take out all the 2's, and then
look up the remaining number to see if it's a power of 5.
So I'm inclined to make normal stringification also produce an exact decimal
by default and only failover to Num if .perl would produce the 1/3 form.
In the absence of an explicit format, I think exactness should trump
limiting the size of the resulting string arbitrarily.
Larry