Skip to content

Instantly share code, notes, and snippets.

@pjlsergeant
Created July 30, 2012 13:24
Show Gist options
  • Select an option

  • Save pjlsergeant/3206885 to your computer and use it in GitHub Desktop.

Select an option

Save pjlsergeant/3206885 to your computer and use it in GitHub Desktop.
Divide by three without using numeric operators...
use strict;
use warnings;
no warnings 'numeric';
print "$_ -> " . div3( $_ ) . "\n" for map { $_ / 10 } 0 .. 10;
print "$_ -> " . div3( $_ ) . "\n" for 0 .. 10;
sub div3 {
my $input = shift;
# Turn it in to its digits, casting in to a string
my @digits = split //, $input;
# Create a 30-item list. This should be done outside the loop, obv
my @lookup = map { [$_,0], [$_,1], [$_,2] } 0 .. 9;
# You could do this more gracefully with reduce, but it's easier to
# understand this way. This is the 'digit' we carry
my $carry = '';
# We'll build up a string output here
my $output = '';
# Have we passed a decmial?
my $float = 0;
# For every digit...
while ( @digits ) {
my $digit = shift( @digits );
# Pass the period through, noting that we're now in floating territory
if ( $digit eq '.' ) {
$float = 1;
$output .= '.';
# Otherwise
} else {
# Concatenate the carry 'digit' and the current 'digit'
$digit = $carry . $digit;
# Lookup how that divides by three
my ( $result, $remainder ) = @{ $lookup[ $digit ] };
# If the remainder is 0, we actually want a zero-length string
$carry = $remainder || '';
# Unless it's a leading 0, add the number to our output
$output .= $result if length( $output ) || $result;
# If we have a carry but are all out of digits, round
if ( $carry && ! @digits ) {
unless ( $float ) { $output .= '.' }
$output .= [1,4,7]->[$carry];
last;
}
}
}
return $output || 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment