Between masak’s Perl 6 contest and the Perl 6 Advent calendar, I haven’t done a lot of blogging here lately. Apologies!

So, a discussion on #perl6 the other day got me thinking about another possible interesting use of the `Real`

role. Here’s the basic class:

class TimesPi does Real { has Real $.x; method new($x) { self.bless(*, :$x); } method Bridge() { $.x * pi; } method Str() { $.x ~ "π"; } method perl() { "({ $.x })π"; } } sub postfix:<π>($x) { TimesPi.new($x); }

So, that’s simple enough, right? TimesPi stores a `Real`

number `$.x`

internally, and the value it represents is that number times pi. There’s a postfix operator π to make it really easy to construct these numbers. Because we’ve defined a `Bridge`

method, this class has access to all the normal methods and operators of `Real`

. Still, as presented above it is pretty useless, but defining some operators hints at a useful purposes for this class.

multi sub infix:<+>(TimesPi $lhs, TimesPi $rhs) { TimesPi.new($lhs.x + $rhs.x); } multi sub infix:<->(TimesPi $lhs, TimesPi $rhs) { TimesPi.new($lhs.x - $rhs.x); } multi sub prefix:<->(TimesPi $n) { TimesPi.new(- $n.x); } multi sub infix:<*>(TimesPi $lhs, Real $rhs) { TimesPi.new($lhs.x * $rhs); } multi sub infix:<*>(Real $lhs, TimesPi $rhs) { TimesPi.new($lhs * $rhs.x); } multi sub infix:<*>(TimesPi $lhs, TimesPi $rhs) { $lhs.Bridge * $rhs.Bridge; } multi sub infix:</>(TimesPi $lhs, Real $rhs) { TimesPi.new($lhs.x / $rhs); } multi sub infix:</>(TimesPi $lhs, TimesPi $rhs) { $lhs.x / $rhs.x; }

With these operators in place, basic arithmetic involving TimesPi numbers will stay in the TimesPi class when appropriate. For instance, if you add two TimesPi numbers, the result will be a TimesPi. The cool thing about this is that it is as exact `$.x`

values allow, rather than forcing everything to be a floating point calculation of limited accuracy.

We can even take things a step further, using this to perform exact trig calculations:

multi method sin(TimesPi $x: $base = Radians) { return $x.Bridge.sin($base) unless $base == Radians; given $x.x { when Int { 0; } when Rat { given $x.x.denominator { when 1 { 0; } when 2 { ($x.x.numerator - 1) %% 4 ?? 1 !! -1 } # could have a case for 6 as well... $x.Bridge.sin; } } default { $x.Bridge.sin; } } }

This checks for cases where we know the exact value of the result, and returns that if it can, otherwise falling back to the standard `Real.sin`

method.

Of course, just when I was feeling like I might be on to something here, I realized that `$.x`

was just the number of degrees in the angle divided by 180. Sigh.

January 19, 2011 at 4:06 pm |

Have you considered parameterizing this on arbitrary irrationals? I can see this being equally useful, for example dealing with √ 2.

January 19, 2011 at 4:11 pm |

The idea had occurred to me, though I didn’t follow the thought very far. I guess it would be pretty easy to do, eh? Hmmm.