Arithmetic-PaperAndPencil

 view release on metacpan or  search on metacpan

doc/documentation.en.md  view on Meta::CPAN

```

I replaced  the dash with an  underline without batting an  eyelid. As
for the signature,  I tried to use  it as is. Perl 5.38  does not like
type declarations  such as `Int`. On  the other hand, once  these type
declarations are removed, Perl  5.38 accepts the parameter declaration
and I was allowed to write:

```
# Perl
sub filling_spaces($l, $c) {
```

instead of

```
# Perl
sub filling_spaces {
  my ($l, $c) = @_;
```

doc/documentation.fr.md  view on Meta::CPAN

sub filling-spaces(Int $l, Int $c) {
```

J'ai changé  le tiret en souligné  sans me poser de  question. Pour la
signature, j'ai  essayé de l'utiliser  telle quelle. Perl  5.38 n'aime
pas les déclarations de type `Int` ou autres. En revanche, il admet la
déclaration des paramètres de fonction et j'ai pu ainsi écrire :

```
# Perl
sub filling_spaces($l, $c) {
```

au lieu de

```
# Perl
sub filling_spaces {
  my ($l, $c) = @_;
```

lib/Arithmetic/PaperAndPencil/Number.pm  view on Meta::CPAN

    return Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => '0');
  }
  else {
    return Arithmetic::PaperAndPencil::Number->new(
          radix => $radix
        , value => substr($value, 0, $self->chars - $len)
        );
  }
}

sub max_unit($radix) {
  if ($radix < 2 or $radix > 36) {
    croak("Radix $radix should be between 2 and 36");
  }
  return Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $digits[$radix - 1]);
}

method _native_int {
  if ($self->chars > 2) {
    croak("Conversion to native allowed only for 1-digit numbers or 2-digit numbers");
  }
  my $tens  = $digit_value{$self->carry->value};
  my $units = $digit_value{$self->unit ->value};
  return $tens * $self->radix + $units;
}

sub add($x, $y, $invert) {
  my $radix = $x->radix;
  if ($radix != $y->radix) {
    croak("Addition not allowed with different bases: $radix @{[$y->radix]}");
  }
  if ($x->chars != 1 and $y->chars != 1) {
    croak("Addition allowed only if at least one number has a single digit");
  }

  my @long_op;
  my $short_op;

lib/Arithmetic/PaperAndPencil/Number.pm  view on Meta::CPAN

      last;
    }
    $long_op[$i] = '0';
  }

  return Arithmetic::PaperAndPencil::Number->new(
        radix => $radix
      , value => join('', reverse(@long_op)));
}

sub minus($x, $y, $invert) {
  if ($invert) {
    ($x, $y) = ($y, $x);
  }
  my $radix = $x->radix;
  if ($radix != $y->radix) {
    croak("Subtraction not allowed with different bases: $radix @{[$y->radix]}");
  }
  if ($x->chars != 1 or $y->chars != 1) {
    croak("Subtraction allowed only for single-digit numbers");
  }
  if ($x->value lt $y->value) {
    croak("The first number must be greater or equal to the second number");
  }
  my $x10 = $x->_native_int;
  my $y10 = $y->_native_int;
  my $z10 = $x10 - $y10;
  return Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $digits[$z10]);
}

sub times($x, $y, $invert) {
  if ($invert) {
    ($x, $y) = ($y, $x);
  }
  my $radix = $x->radix;
  if ($radix != $y->radix) {
    croak("Multiplication not allowed with different bases: $radix @{[$y->radix]}");
  }
  if ($x->chars != 1 or $y->chars != 1) {
    croak("Multiplication allowed only for single-digit numbers");
  }
  my $x10 = $x->_native_int;
  my $y10 = $y->_native_int;
  my $z10 = $x10 * $y10;
  my $zu  = $z10 % $radix;
  my $zt  = floor($z10 / $radix);
  return Arithmetic::PaperAndPencil::Number->new(value => $digits[$zt] . $digits[$zu]
                                               , radix => $radix);
}

sub divide($x, $y, $invert) {
  if ($invert) {
    ($x, $y) = ($y, $x);
  }
  my $radix = $x->radix;
  if ($radix != $y->radix) {
    croak("Division not allowed with different bases: $radix @{[$y->radix]}");
  }
  if ($x->chars > 2) {
    croak("The dividend must be a 1- or 2-digit number");
  }

lib/Arithmetic/PaperAndPencil/Number.pm  view on Meta::CPAN

  if ($qq >= $radix) {
    my $q0 = $qq % $radix;
    my $q1 = floor($qq / $radix);
    return Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $digits[$q1] . $digits[$q0]);
  }
  else {
    return Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $digits[$qq]);
  }
}

sub num_cmp($x, $y, $invert) {
  my $radix = $x->radix;
  if ($radix != $y->radix) {
    croak("Comparison not allowed with different bases: $radix @{[$y->radix]}");
  }
  return $x->chars <=> $y->chars
                   ||
         $x->value cmp $y->value;
}

sub alpha_cmp($x, $y, $invert) {
  my $radix = $x->radix;
  if ($radix != $y->radix) {
    croak("Comparison not allowed with different bases: $radix @{[$y->radix]}");
  }
  return $x->value cmp $y->value;
}

use overload '+' => \&add
           , '-' => \&minus
           , '*' => \&times

xt/02-html.t  view on Meta::CPAN

is($html, $ref);

$html = $operation->html(lang => 'en', silent => 0, level => 0);
$ref = slurp('xt/data/02-html-en-talk.html');
is($html, $ref);

$html = $operation->html(lang => 'en', silent => 1, level => 0);
$ref = slurp('xt/data/02-html-en-silent.html');
is($html, $ref);

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/03-number.t  view on Meta::CPAN


for (@test_div) {
  check_div(@$_);
}

for (@test_odd) {
  check_odd(@$_);
}
done_testing;

sub check_add($radix, $x, $y, $sum) {
  my $xx = Arithmetic::PaperAndPencil::Number->new(value => $x, radix => $radix);
  my $yy = Arithmetic::PaperAndPencil::Number->new(value => $y, radix => $radix);
  my $zz = $xx + $yy;
  is($zz->value, $sum, "$x plus $y is $sum (radix $radix)");
}

sub check_mult($radix, $x, $y, $pdt) {
  my $xx = Arithmetic::PaperAndPencil::Number->new(value => $x, radix => $radix);
  my $yy = Arithmetic::PaperAndPencil::Number->new(value => $y, radix => $radix);
  my $zz = $xx * $yy;
  is( $zz->value, $pdt, "$x times $y is $pdt (radix $radix)");
}

sub check_sub($radix, $x, $y, $x1, $s) {
  my $xx = Arithmetic::PaperAndPencil::Number->new(value => $x, radix => $radix);
  my $yy = Arithmetic::PaperAndPencil::Number->new(value => $y, radix => $radix);
  my $x_adj;
  my $rem;
  ($x_adj, $rem) = adjust_sub($xx, $yy);
  is( $x_adj->value, $x1, "$x - $y : adjusted to $x1 - $y (radix $radix)");
  is( $rem->value,   $s , "$x1 - $y = $s (radix $radix)");
}

sub check_cmp($radix, $len, $orig, $dest) {
  my $x =  Arithmetic::PaperAndPencil::Number->new(value => $orig, radix => $radix);
  my $y  = $x->complement($len);
  is( $y->value, $dest, "$radix-complement of @{[$x->value]} is $dest");

}

sub check_div($radix, $dividend, $divisor, $quotient) {
  my $x = Arithmetic::PaperAndPencil::Number->new(value => $dividend, radix => $radix);
  my $y = Arithmetic::PaperAndPencil::Number->new(value => $divisor , radix => $radix);
  my $z = $x / $y;
  is($z->value, $quotient, "$dividend / $divisor = $quotient (radix $radix)");
}

sub check_odd($radix, $value, $result) {
  my $x = Arithmetic::PaperAndPencil::Number->new(value => $value, radix => $radix);
  my $comment = "even";
  if ($result) {
    $comment = "odd";
  }
  is( 0+ $x->is_odd, $result, "$value (radix $radix) is $comment");
}

xt/06-subtraction.t  view on Meta::CPAN

for my $data (@tests) {
  my ($radix, $high, $low, $result) = @$data;
  check_sub($radix, $high, $low, $result);
}


is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html();
is($html, $refhtml, "Checking HTML file");

sub check_sub($radix, $high1, $low1, $result1) {

  my $high  =  Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $high1);
  my $low   =  Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $low1);
  my $result = $operation->subtraction(high => $high, low => $low);
  is($result->value, $result1, "$high1 - $low1 = $result1 (radix $radix)");
  $result = $operation->subtraction(high => $high, low => $low, type => 'compl');
  is($result->value, $result1, "$high1 - $low1 = $result1 (adding the $radix complement)");
}

xt/07-mult.t  view on Meta::CPAN

$pdt = $operation->multiplication(multiplicand => $y, multiplier => $x, type => 'std'       ); is($pdt->value, '2187');
$pdt = $operation->multiplication(multiplicand => $x, multiplier => $y, type => 'jalousie-A'); is($pdt->value, '2187');
$pdt = $operation->multiplication(multiplicand => $x, multiplier => $y, type => 'jalousie-B'); is($pdt->value, '2187');
$pdt = $operation->multiplication(multiplicand => $x, multiplier => $z, type => 'jalousie-A', product => 'straight'); is($pdt->value, '89667');
$pdt = $operation->multiplication(multiplicand => $x, multiplier => $z, type => 'jalousie-B', product => 'straight'); is($pdt->value, '89667');

is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 2);
is($html, $refhtml, "Checking HTML file");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/08-mult.t  view on Meta::CPAN


$pdt = $operation->multiplication(multiplicand => $x, multiplier => $x, type => 'std');
is($pdt->value, '104046120906024001600000000', "product is 104046120906024001600000000");
$pdt = $operation->multiplication(multiplicand => $y, multiplier => $z, type => 'std');
is($pdt->value, '202', "product is 202");

is($operation->csv, $refcsv, "checking the CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 3);
is($html, $refhtml, "checking the HTML file");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/09-mult-shortcut.t  view on Meta::CPAN

$pdt = $operation->multiplication(multiplicand => $x, multiplier => $x, type => 'shortcut');
is($pdt->value, '19999999932878736', "Square of 141421356 is 19999999932878736");

$pdt = $operation->multiplication(multiplicand => $y, multiplier => $y, type => 'shortcut');
is($pdt->value, '500000000000094050625', "Square of 22360679775 is 500000000000094050625");

is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 3);
is($html, $refhtml, "Checking HTML file");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/10-mult-prepared.t  view on Meta::CPAN

$pdt = $operation->multiplication(multiplicand => $x, multiplier => $x, type => 'prepared');
is($pdt->value, '19999999932878736', "Square of 141421356 is 19999999932878736");

$pdt = $operation->multiplication(multiplicand => $y, multiplier => $y, type => 'prepared');
is($pdt->value, '1800000156197669498944', "Square of 42426408712 is 1800000156197669498944");

is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 3);
is($html, $refhtml, "Checking HTML file");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/11-mult-boat.t  view on Meta::CPAN


$x = Arithmetic::PaperAndPencil::Number->new(value => '345');
$y = Arithmetic::PaperAndPencil::Number->new(value => '333');
$pdt = $operation->multiplication(multiplicand => $x, multiplier => $y, type => 'boat', mult_and_add => 'combined', direction => 'rtl');
is($pdt->value, '114885', '333 times 345 is 114885');

is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 4);
is($html, $refhtml, "Checking HTML file");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/12-russ-mult.t  view on Meta::CPAN

  is($pd1->value, $pdt, "$md × $mr = $pdt (radix $radix)");
}

my $html = $operation->html(lang => 'fr', silent => 0, level => 3);
my $refcsv  = slurp('xt/data/12-russ-mult.csv' );
my $refhtml = slurp('xt/data/12-russ-mult.html');

is($operation->csv, $refcsv, "Checking CSV file");
is($html, $refhtml, "Checking HTML file");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/13-prep-division.t  view on Meta::CPAN

is($result->value, '1006', "26048000 divided by 25882 is 1006 (short hook, two inner zeroes)");

$dividend = Arithmetic::PaperAndPencil::Number->new(radix => 10, value => '26399640');
$result = $operation->division(dividend => $dividend, divisor => $divisor, type => 'prepared');
is($result->value, '1020', "26399640 divided by 25882 is 1020 (short hook, one inner zero and one final zero)");

is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 3);
is($html, $refhtml, "Checking HTML file");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/14-division.t  view on Meta::CPAN

$result = $operation->division(dividend => $x, divisor => $one);                      is($result->value, '9212', "division by 1 is obvious");
$result = $operation->division(dividend => $y, divisor => $x);                        is($result->value, '0'   , "division of a small dividend by a large divisor is obvious");
$result = $operation->division(dividend => $x, divisor => $y, result => 'remainder'); is($result->value, '38'  , "9212 divided by 139 gives 66, remainder 38");
$result = $operation->division(dividend => $x, divisor => $y, type   => 'cheating');  is($result->value, '66'  , "9212 divided by 139 gives 66");
$result = $operation->division(dividend => $x1, divisor => $y);                       is($result->value, '728' , "101212 divided by 139 gives 728");

is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 4);
is($html, $refhtml, "Checking HTML file");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/15-division.t  view on Meta::CPAN

is($result->value, '38', "9212 divided by 139 gives 66, remainder 38");
$result = $operation->division(dividend => $x, divisor => $y, type => 'cheating', mult_and_sub => 'separate');
is($result->value, '66', "9212 divided by 139 gives 66");
$result = $operation->division(dividend => $x1, divisor => $y, mult_and_sub => 'separate');
is($result->value, '728', "101212 divided by 139 gives 728");

is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 4);
is($html, $refhtml, "Checking HTML file");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/16-div-boat.t  view on Meta::CPAN


for my $data (@tests) {
  my ($radix, $dividend, $divisor, $quotient, $remainder) = @$data;
  check_div($radix,  $dividend, $divisor, $quotient, $remainder);
}
is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 5);
is($html, $refhtml, "Checking HTML file");
done_testing;

sub check_div($radix, $dividend1, $divisor1, $quotient, $remainder) {

  my $dividend  = Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $dividend1);
  my $divisor   = Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $divisor1 );
  my Arithmetic::PaperAndPencil::Number $result;
  $result = $operation->division(type => 'boat', dividend => $dividend, divisor => $divisor);
  is($result->value, $quotient, "$dividend1 divided by $divisor1 is $quotient");
  $result = $dummy_op->division(type => 'boat', dividend => $dividend, divisor => $divisor, result=> 'remainder');
  is($result->value, $remainder, "$dividend1 divided by $divisor1 is $quotient, remaining $remainder");

}

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/17-square-root.t  view on Meta::CPAN

  check_sqrt_sep($radix, $number, $result);
}


is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 4);
is($html, $refhtml, "Checking HTML file");

done_testing;

sub check_sqrt($radix, $number1, $result1) {
  my $number = Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $number1);
  my Arithmetic::PaperAndPencil::Number $result;
  $result = $operation->square_root($number);
  is($result->value, $result1, "sqrt @{[$number->value]} = $result1 (radix $radix)");
}

sub check_sqrt_sep($radix, $number1, $result1) {
  my $number = Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $number1);
  my Arithmetic::PaperAndPencil::Number $result;
  $result = $operation->square_root($number, mult_and_sub => 'separate');
  is($result->value, $result1, "sqrt @{[$number->value]} = $result1 (radix $radix)");
}

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/18-conversion.t  view on Meta::CPAN

$result = $operation->conversion(number => $z, radix => 10, nb_op => 2); is($result->value,     '34', "Single digit, but still not an obvious conversion");
$result = $operation->conversion(number => $z, radix =>  2, nb_op => 2); is($result->value, '100010', "Single digit, but still not an obvious conversion");
$result = $operation->conversion(number => $t, radix => 16, nb_op => 2); is($result->value,    'FFF', "Not an obvious conversion (except if you are a geek)");
$result = $operation->conversion(number => $t, radix =>  8, nb_op => 2); is($result->value,   '7777', "Not an obvious conversion (except if you are a geek)");
$result = $operation->conversion(number => $t, radix =>  8);             is($result->value,   '7777', "Conversion without changing page");

is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 4);
is($html, $refhtml, "Checking HTML file");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/19-conversion-div.t  view on Meta::CPAN

is($result->value, 'DEADBEEF', "3735928559(10) -> DEADBEEF(16)");
$result = $operation->conversion(number => $z, radix => 16, nb_op => 2, type => 'div', div_type => 'cheating', mult_and_sub => 'separate');
is($result->value, 'DEADBEEF', "3735928559(10) -> DEADBEEF(16)");

is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 4);
is($html, $refhtml1, "Checking HTML file with level 4");
$html = $operation->html(lang => 'fr', silent => 0, level => 6);
is($html, $refhtml2, "Checking HTML file with level 6");

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}

xt/20-gcd.t  view on Meta::CPAN

for my $data (@tests) {
  my ($radix, $first, $second, $result) = @$data;
  check_gcd_cheat($radix, $first, $second, $result);
}


is($operation->csv, $refcsv, "Checking CSV file");
my $html = $operation->html(lang => 'fr', silent => 0, level => 6);
is($html, $refhtml, "Checking HTML file");

sub check_gcd_std($radix, $first1, $second1, $result1) {
  my $first   = Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $first1);
  my $second  = Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $second1);
  my Arithmetic::PaperAndPencil::Number $result;
  $result = $operation->gcd(first => $first, second => $second);
  is($result->value, $result1, "gcd(@{[$first->value]}, @{[$second->value]}) = $result1 (radix $radix)");
}

sub check_gcd_cheat($radix, $first1, $second1, $result1) {
  my $first   = Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $first1);
  my $second  = Arithmetic::PaperAndPencil::Number->new(radix => $radix, value => $second1);
  my Arithmetic::PaperAndPencil::Number $result;
  $result = $operation->gcd(first => $first, second => $second, div_type => 'cheating');
  is($result->value, $result1, "gcd(@{[$first->value]}, @{[$second->value]}) = $result1 (radix $radix)");
}

sub slurp($fname) {
  open my $f, '<', $fname
    or die "Opening $fname $!";
  $/ = undef;
  my $result = <$f>;
  close $f
    or die "Closing $fname $!";
  return $result;
}



( run in 0.483 second using v1.01-cache-2.11-cpan-65fba6d93b7 )