Skip to content

Commit

Permalink
Fixes to bigint 32bit (#4922)
Browse files Browse the repository at this point in the history
* fixes for 32bit platform

* additional fixes for 32bit platform
  • Loading branch information
akzhan authored and RX14 committed Sep 9, 2017
1 parent c307051 commit 46197bd
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 13 deletions.
6 changes: 6 additions & 0 deletions spec/std/big/big_int_spec.cr
Expand Up @@ -81,6 +81,8 @@ describe "BigInt" do
(1.to_big_i + 2).should eq(3.to_big_i)
(1.to_big_i + 2_u8).should eq(3.to_big_i)
(5.to_big_i + (-2_i64)).should eq(3.to_big_i)
(5.to_big_i + Int64::MAX).should be > Int64::MAX.to_big_i
(5.to_big_i + Int64::MAX).should eq(Int64::MAX.to_big_i + 5)

(2 + 1.to_big_i).should eq(3.to_big_i)
end
Expand All @@ -90,6 +92,8 @@ describe "BigInt" do
(5.to_big_i - 2).should eq(3.to_big_i)
(5.to_big_i - 2_u8).should eq(3.to_big_i)
(5.to_big_i - (-2_i64)).should eq(7.to_big_i)
(-5.to_big_i - Int64::MAX).should be < -Int64::MAX.to_big_i
(-5.to_big_i - Int64::MAX).should eq(-Int64::MAX.to_big_i - 5)

(5 - 1.to_big_i).should eq(4.to_big_i)
(-5 - 1.to_big_i).should eq(-6.to_big_i)
Expand All @@ -105,6 +109,7 @@ describe "BigInt" do
(2.to_big_i * 3_u8).should eq(6.to_big_i)
(3 * 2.to_big_i).should eq(6.to_big_i)
(3_u8 * 2.to_big_i).should eq(6.to_big_i)
(2.to_big_i * Int64::MAX).should eq(2.to_big_i * Int64::MAX.to_big_i)
end

it "gets absolute value" do
Expand All @@ -115,6 +120,7 @@ describe "BigInt" do
(10.to_big_i / 3.to_big_i).should eq(3.to_big_i)
(10.to_big_i / 3).should eq(3.to_big_i)
(10 / 3.to_big_i).should eq(3.to_big_i)
((Int64::MAX.to_big_i * 2.to_big_i) / Int64::MAX).should eq(2.to_big_i)
end

it "divides with negative numbers" do
Expand Down
52 changes: 39 additions & 13 deletions src/big/big_int.cr
Expand Up @@ -106,8 +106,10 @@ struct BigInt < Int
def +(other : Int) : BigInt
if other < 0
self - other.abs
else
elsif other <= LibGMP::ULong::MAX
BigInt.new { |mpz| LibGMP.add_ui(mpz, self, other) }
else
self + other.to_big_i
end
end

Expand All @@ -118,8 +120,10 @@ struct BigInt < Int
def -(other : Int) : BigInt
if other < 0
self + other.abs
else
elsif other <= LibGMP::ULong::MAX
BigInt.new { |mpz| LibGMP.sub_ui(mpz, self, other) }
else
self - other.to_big_i
end
end

Expand All @@ -135,14 +139,18 @@ struct BigInt < Int
BigInt.new { |mpz| LibGMP.mul(mpz, self, other) }
end

def *(other : Int::Signed) : BigInt
def *(other : LibGMP::IntPrimitiveSigned) : BigInt
BigInt.new { |mpz| LibGMP.mul_si(mpz, self, other) }
end

def *(other : Int::Unsigned) : BigInt
def *(other : LibGMP::IntPrimitiveUnsigned) : BigInt
BigInt.new { |mpz| LibGMP.mul_ui(mpz, self, other) }
end

def *(other : Int) : BigInt
self * other.to_big_i
end

def /(other : Int) : BigInt
check_division_by_zero other

Expand All @@ -156,27 +164,35 @@ struct BigInt < Int
def tdiv(other : Int) : BigInt
check_division_by_zero other

if other < 0
-self.unsafe_truncated_div(other)
else
unsafe_truncated_div(other)
end
unsafe_truncated_div(other)
end

def unsafe_floored_div(other : BigInt) : BigInt
BigInt.new { |mpz| LibGMP.fdiv_q(mpz, self, other) }
end

def unsafe_floored_div(other : Int) : BigInt
BigInt.new { |mpz| LibGMP.fdiv_q_ui(mpz, self, other.abs) }
if LibGMP::ULong == UInt32 && (other < Int32::MIN || other > UInt32::MAX)
unsafe_floored_div(other.to_big_i)
elsif other < 0
-BigInt.new { |mpz| LibGMP.fdiv_q_ui(mpz, self, other.abs) }
else
BigInt.new { |mpz| LibGMP.fdiv_q_ui(mpz, self, other) }
end
end

def unsafe_truncated_div(other : BigInt) : BigInt
BigInt.new { |mpz| LibGMP.tdiv_q(mpz, self, other) }
end

def unsafe_truncated_div(other : Int) : BigInt
BigInt.new { |mpz| LibGMP.tdiv_q_ui(mpz, self, other.abs) }
if LibGMP::ULong == UInt32 && (other < Int32::MIN || other > UInt32::MAX)
unsafe_truncated_div(other.to_big_i)
elsif other < 0
-BigInt.new { |mpz| LibGMP.tdiv_q_ui(mpz, self, other.abs) }
else
BigInt.new { |mpz| LibGMP.tdiv_q_ui(mpz, self, other) }
end
end

def %(other : Int) : BigInt
Expand Down Expand Up @@ -229,17 +245,27 @@ struct BigInt < Int
end

def unsafe_floored_mod(other : Int) : BigInt
BigInt.new { |mpz| LibGMP.fdiv_r_ui(mpz, self, other.abs) }
if (other < LibGMP::Long::MIN || other > LibGMP::ULong::MAX)
unsafe_floored_mod(other.to_big_i)
elsif other < 0
-BigInt.new { |mpz| LibGMP.fdiv_r_ui(mpz, self, other.abs) }
else
BigInt.new { |mpz| LibGMP.fdiv_r_ui(mpz, self, other) }
end
end

def unsafe_truncated_mod(other : BigInt) : BigInt
BigInt.new { |mpz| LibGMP.tdiv_r(mpz, self, other) }
end

def unsafe_truncated_mod(other : Int) : BigInt
def unsafe_truncated_mod(other : LibGMP::IntPrimitive) : BigInt
BigInt.new { |mpz| LibGMP.tdiv_r_ui(mpz, self, other.abs) }
end

def unsafe_truncated_mod(other : Int) : BigInt
BigInt.new { |mpz| LibGMP.tdiv_r_ui(mpz, self, other.abs.to_big_i) }
end

def unsafe_floored_divmod(number : BigInt)
the_q = BigInt.new
the_r = BigInt.new { |r| LibGMP.fdiv_qr(the_q, r, self, number) }
Expand Down
4 changes: 4 additions & 0 deletions src/big/lib_gmp.cr
Expand Up @@ -7,6 +7,10 @@ lib LibGMP
alias Double = LibC::Double
alias BitcntT = ULong

alias IntPrimitiveSigned = Int8 | Int16 | Int32 | LibC::Long
alias IntPrimitiveUnsigned = UInt8 | UInt16 | UInt32 | LibC::ULong
alias IntPrimitive = IntPrimitiveSigned | IntPrimitiveUnsigned

{% if flag?(:x86_64) || flag?(:aarch64) %}
alias MpExp = Int64
{% else %}
Expand Down

0 comments on commit 46197bd

Please sign in to comment.