Skip to content

Commit

Permalink
- Added the Number.base() method to return the self number in as a st…
Browse files Browse the repository at this point in the history
…ring in a given base.

Example:
	say 255.base(16);	# prints: "ff"

- Improved the Number.as_oct(), Number.as_bin() and Number.as_hex() methods to no longer use Math::BigInt for conversion.
- Improved the String.bin(), String.oct() and String.hex() methods to support big integers.
  • Loading branch information
trizen committed Dec 29, 2015
1 parent b93392a commit 33df118
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 84 deletions.
51 changes: 19 additions & 32 deletions lib/Sidef/Types/Number/Number.pm
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,6 @@ package Sidef::Types::Number::Number {
q{0+} => sub { Math::GMPq::Rmpq_get_d(${$_[0]}) },
q{""} => \&get_value;

sub _load_bigint {
state $bigint = do {
require Math::BigInt;
Math::BigInt->import(try => 'GMP');
};
}

sub _load_bigrat {
state $bigrat = do {
require Math::BigRat;
Expand Down Expand Up @@ -214,6 +207,22 @@ package Sidef::Types::Number::Number {
}
}

sub base {
my ($x, $y) = @_;
_valid($y);

state $min = Math::GMPq->new(2);
state $max = Math::GMPq->new(36);

if (Math::GMPq::Rmpq_cmp($$y, $min) < 0 or Math::GMPq::Rmpq_cmp($$y, $max) > 0) {
die "[ERROR] base must be between 2 and 36, got $$y\n";
}

Sidef::Types::String::String->new(Math::GMPq::Rmpq_get_str(${$_[0]}, $$y));
}

*in_base = \&base;

sub _get_frac {
Math::GMPq::Rmpq_get_str(${$_[0]}, 10);
}
Expand Down Expand Up @@ -1119,41 +1128,19 @@ package Sidef::Types::Number::Number {
sub as_bin {
my $z = Math::GMPz::Rmpz_init();
Math::GMPz::Rmpz_set_q($z, ${$_[0]});
state $bigint = _load_bigint();
Sidef::Types::String::String->new(substr(Math::BigInt->new(Math::GMPz::Rmpz_get_str($z, 10))->as_bin, 2));
Sidef::Types::String::String->new(Math::GMPz::Rmpz_get_str($z, 2));
}

sub as_oct {
my $z = Math::GMPz::Rmpz_init();
Math::GMPz::Rmpz_set_q($z, ${$_[0]});
state $bigint = _load_bigint();
Sidef::Types::String::String->new(substr(Math::BigInt->new(Math::GMPz::Rmpz_get_str($z, 10))->as_oct, 1));
Sidef::Types::String::String->new(Math::GMPz::Rmpz_get_str($z, 8));
}

sub as_hex {
my $z = Math::GMPz::Rmpz_init();
Math::GMPz::Rmpz_set_q($z, ${$_[0]});
state $bigint = _load_bigint();
Sidef::Types::String::String->new(substr(Math::BigInt->new(Math::GMPz::Rmpz_get_str($z, 10))->as_hex, 2));
}

sub bin {
my $z = Math::GMPz::Rmpz_init();
Math::GMPz::Rmpz_set_q($z, ${$_[0]});

my $r = Math::GMPz::Rmpz_init();
my @digits =
grep { $_ eq '0' or $_ eq '1' or die "[ERROR] Non-binary digit detected inside number `$z` in Number.bin()\n" }
split(//, scalar reverse Math::GMPz::Rmpz_get_str($z, 10));

foreach my $i (0 .. $#digits) {
if ($digits[$i] eq '1') {
my $tmp = Math::GMPz::Rmpz_init();
Math::GMPz::Rmpz_ui_pow_ui($tmp, 2, $i);
Math::GMPz::Rmpz_add($r, $r, $tmp);
}
}
_mpz2rat($r);
Sidef::Types::String::String->new(Math::GMPz::Rmpz_get_str($z, 16));
}

sub digits {
Expand Down
17 changes: 7 additions & 10 deletions lib/Sidef/Types/String/String.pm
Original file line number Diff line number Diff line change
Expand Up @@ -347,29 +347,26 @@ package Sidef::Types::String::String {
$self->new(crypt($$self, $salt->get_value));
}

sub hex {
sub bin {
my ($self) = @_;
Sidef::Types::Number::Number->new(CORE::hex($$self));
Sidef::Types::Number::Number->new($$self, 2);
}

sub oct {
my ($self) = @_;
Sidef::Types::Number::Number->new(CORE::oct($$self));
Sidef::Types::Number::Number->new($$self, 8);
}

sub bin {
sub num {
my ($self) = @_;
my $value = $$self;
Sidef::Types::Number::Number->new(CORE::oct(index($value, '0b') == 0 ? $value : ('0b' . $value)));
Sidef::Types::Number::Number->new($$self, 10);
}

sub num {
sub hex {
my ($self) = @_;
Sidef::Types::Number::Number->new($$self);
Sidef::Types::Number::Number->new($$self, 16);
}

*dec = \&num;

sub substr {
my ($self, $offs, $len) = @_;
__PACKAGE__->new(
Expand Down
2 changes: 1 addition & 1 deletion scripts/Project Euler/0033-digit_cancelling_fractions.sf
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# Answer: 100

var prod = 1.rat;
var prod = 1;

9.times { |i|
9.times { |j|
Expand Down
26 changes: 0 additions & 26 deletions scripts/Project Euler/0071-ordered_fractions.sf
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,3 @@ func before_numerator(b, n, d, m) {
}

say before_numerator(2, 3, 7, 1e6);


__END__
#
## Brute-force solution:
#

var max = 35;

var fractions = [];
range(1, max-1).each { |n|
range(n+1, max).each { |d|
fractions << (n.rat / d.rat);
}
}

var last 0.rat;
var wfr = 3.rat/7.rat;

fractions.sort.each { |f|
if (f == wfr) {
say (last, " => ", last.numerator);
break;
}
last = f;
}
20 changes: 7 additions & 13 deletions scripts/Tests/string_to_number.sf
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
#!/usr/bin/ruby

var dec = '0123459';
var hex_noprefix = 'abcf123';
var hex_withprefix = '0xabcf123';
var oct_noprefix = '7651';
var oct_withprefix = '07651';
var bin_noprefix = '101011001';
var bin_withprefix = '0b101011001';
var dec = '0123459';
var hex = 'abcf123';
var oct = '7651';
var bin = '101011001';

assert_eq( 123459, dec.num);
assert_eq(180154659, hex_noprefix.hex);
assert_eq(180154659, hex_withprefix.hex);
assert_eq( 4009, oct_noprefix.oct);
assert_eq( 4009, oct_withprefix.oct);
assert_eq( 345, bin_noprefix.bin);
assert_eq( 345, bin_withprefix.bin);
assert_eq(180154659, hex.hex);
assert_eq( 4009, oct.oct);
assert_eq( 345, bin.bin);

say "** Test passed!";
4 changes: 2 additions & 2 deletions scripts/bernoulli_numbers.sf
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
func bernoulli_print {
var a = [];
range(0, 20).each { |m|
a.append(1.rat / rat(m+1));
a.append(1 / m+1);
range(m, 1, -1).each { |j|
a[j-1] = (j.rat * (a[j-1] - a[j]));
a[j-1] = (j * (a[j-1] - a[j]));
}
a[0] || next;
printf("B(%2d) = %20s / %s\n", m, a[0].parts);
Expand Down

0 comments on commit 33df118

Please sign in to comment.