mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
math.big: add checked division methods (#18924)
This commit is contained in:
parent
4a543c5f51
commit
7b306e9b8f
@ -573,6 +573,11 @@ fn test_div_mod() {
|
|||||||
assert q == eq
|
assert q == eq
|
||||||
assert r == er
|
assert r == er
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// an extra test for checked division by zero
|
||||||
|
if _, _ := div_mod_test_data[0].dividend.parse().div_mod_checked(TestInteger(0).parse()) {
|
||||||
|
assert false, 'Division by 0 should return an error'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_comparison() {
|
fn test_comparison() {
|
||||||
|
@ -369,12 +369,16 @@ pub fn (multiplicand Integer) * (multiplier Integer) Integer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// div_mod returns the quotient and remainder from the division of the integers `dividend` divided by `divisor`.
|
// div_mod_internal is an entirely unchecked (in terms of division by zero) method for division.
|
||||||
pub fn (dividend Integer) div_mod(divisor Integer) (Integer, Integer) {
|
// This should only be used for internal calculations involving a definitive non-zero
|
||||||
// Quick exits
|
// divisor.
|
||||||
if divisor.signum == 0 {
|
//
|
||||||
panic('Cannot divide by zero')
|
// DO NOT use this method if the divisor has any chance of being 0.
|
||||||
|
fn (dividend Integer) div_mod_internal(divisor Integer) (Integer, Integer) {
|
||||||
|
$if debug {
|
||||||
|
assert divisor.signum != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if dividend.signum == 0 {
|
if dividend.signum == 0 {
|
||||||
return zero_int, zero_int
|
return zero_int, zero_int
|
||||||
}
|
}
|
||||||
@ -382,11 +386,11 @@ pub fn (dividend Integer) div_mod(divisor Integer) (Integer, Integer) {
|
|||||||
return dividend.clone(), zero_int
|
return dividend.clone(), zero_int
|
||||||
}
|
}
|
||||||
if divisor.signum == -1 {
|
if divisor.signum == -1 {
|
||||||
q, r := dividend.div_mod(divisor.neg())
|
q, r := dividend.div_mod_internal(divisor.neg())
|
||||||
return q.neg(), r
|
return q.neg(), r
|
||||||
}
|
}
|
||||||
if dividend.signum == -1 {
|
if dividend.signum == -1 {
|
||||||
q, r := dividend.neg().div_mod(divisor)
|
q, r := dividend.neg().div_mod_internal(divisor)
|
||||||
if r.signum == 0 {
|
if r.signum == 0 {
|
||||||
return q.neg(), zero_int
|
return q.neg(), zero_int
|
||||||
} else {
|
} else {
|
||||||
@ -408,18 +412,64 @@ pub fn (dividend Integer) div_mod(divisor Integer) (Integer, Integer) {
|
|||||||
return quotient, remainder
|
return quotient, remainder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// div_mod returns the quotient and remainder from the division of the integers `dividend`
|
||||||
|
// divided by `divisor`.
|
||||||
|
//
|
||||||
|
// WARNING: this method will panic if `divisor == 0`. Refer to div_mod_checked for a safer version.
|
||||||
|
[inline]
|
||||||
|
pub fn (dividend Integer) div_mod(divisor Integer) (Integer, Integer) {
|
||||||
|
if _unlikely_(divisor.signum == 0) {
|
||||||
|
panic('math.big: Cannot divide by zero')
|
||||||
|
}
|
||||||
|
return dividend.div_mod_internal(divisor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// div_mod_checked returns the quotient and remainder from the division of the integers `dividend`
|
||||||
|
// divided by `divisor`. An error is returned if `divisor == 0`.
|
||||||
|
[inline]
|
||||||
|
pub fn (dividend Integer) div_mod_checked(divisor Integer) !(Integer, Integer) {
|
||||||
|
if _unlikely_(divisor.signum == 0) {
|
||||||
|
return error('math.big: Cannot divide by zero')
|
||||||
|
}
|
||||||
|
return dividend.div_mod_internal(divisor)
|
||||||
|
}
|
||||||
|
|
||||||
// / returns the quotient of `dividend` divided by `divisor`.
|
// / returns the quotient of `dividend` divided by `divisor`.
|
||||||
|
//
|
||||||
|
// WARNING: this method will panic if `divisor == 0`. For a division method that returns a Result
|
||||||
|
// refer to `div_checked`.
|
||||||
|
[inline]
|
||||||
pub fn (dividend Integer) / (divisor Integer) Integer {
|
pub fn (dividend Integer) / (divisor Integer) Integer {
|
||||||
q, _ := dividend.div_mod(divisor)
|
q, _ := dividend.div_mod(divisor)
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
// % returns the remainder of `dividend` divided by `divisor`.
|
// % returns the remainder of `dividend` divided by `divisor`.
|
||||||
|
//
|
||||||
|
// WARNING: this method will panic if `divisor == 0`. For a modular division method that
|
||||||
|
// returns a Result refer to `mod_checked`.
|
||||||
|
[inline]
|
||||||
pub fn (dividend Integer) % (divisor Integer) Integer {
|
pub fn (dividend Integer) % (divisor Integer) Integer {
|
||||||
_, r := dividend.div_mod(divisor)
|
_, r := dividend.div_mod(divisor)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// div_checked returns the quotient of `dividend` divided by `divisor`
|
||||||
|
// or an error if `divisor == 0`.
|
||||||
|
[inline]
|
||||||
|
pub fn (dividend Integer) div_checked(divisor Integer) !Integer {
|
||||||
|
q, _ := dividend.div_mod_checked(divisor)!
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
// mod_checked returns the remainder of `dividend` divided by `divisor`
|
||||||
|
// or an error if `divisor == 0`.
|
||||||
|
[inline]
|
||||||
|
pub fn (dividend Integer) mod_checked(divisor Integer) !Integer {
|
||||||
|
_, r := dividend.div_mod_checked(divisor)!
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// mask_bits is the equivalent of `a % 2^n` (only when `a >= 0`), however doing a full division
|
// mask_bits is the equivalent of `a % 2^n` (only when `a >= 0`), however doing a full division
|
||||||
// run for this would be a lot of work when we can simply "cut off" all bits to the left of
|
// run for this would be a lot of work when we can simply "cut off" all bits to the left of
|
||||||
// the `n`th bit.
|
// the `n`th bit.
|
||||||
@ -791,7 +841,7 @@ pub fn (integer Integer) hex() string {
|
|||||||
|
|
||||||
// radix_str returns the string representation of the integer `a` in the specified radix.
|
// radix_str returns the string representation of the integer `a` in the specified radix.
|
||||||
pub fn (integer Integer) radix_str(radix u32) string {
|
pub fn (integer Integer) radix_str(radix u32) string {
|
||||||
if integer.signum == 0 {
|
if integer.signum == 0 || radix == 0 {
|
||||||
return '0'
|
return '0'
|
||||||
}
|
}
|
||||||
return match radix {
|
return match radix {
|
||||||
@ -808,6 +858,9 @@ pub fn (integer Integer) radix_str(radix u32) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (integer Integer) general_radix_str(radix u32) string {
|
fn (integer Integer) general_radix_str(radix u32) string {
|
||||||
|
$if debug {
|
||||||
|
assert radix != 0
|
||||||
|
}
|
||||||
divisor := integer_from_u32(radix)
|
divisor := integer_from_u32(radix)
|
||||||
|
|
||||||
mut current := integer.abs()
|
mut current := integer.abs()
|
||||||
@ -815,7 +868,7 @@ fn (integer Integer) general_radix_str(radix u32) string {
|
|||||||
mut digit := zero_int
|
mut digit := zero_int
|
||||||
mut rune_array := []rune{cap: current.digits.len * 4}
|
mut rune_array := []rune{cap: current.digits.len * 4}
|
||||||
for current.signum > 0 {
|
for current.signum > 0 {
|
||||||
new_current, digit = current.div_mod(divisor)
|
new_current, digit = current.div_mod_internal(divisor)
|
||||||
rune_array << big.digit_array[digit.int()]
|
rune_array << big.digit_array[digit.int()]
|
||||||
unsafe { digit.free() }
|
unsafe { digit.free() }
|
||||||
unsafe { current.free() }
|
unsafe { current.free() }
|
||||||
@ -1034,7 +1087,8 @@ fn (a Integer) mod_inv(m Integer) Integer {
|
|||||||
q, r := if n.bit_len() == b.bit_len() {
|
q, r := if n.bit_len() == b.bit_len() {
|
||||||
one_int, n - b
|
one_int, n - b
|
||||||
} else {
|
} else {
|
||||||
n.div_mod(b)
|
// safe because the loop terminates if b == 0
|
||||||
|
n.div_mod_internal(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
n = b
|
n = b
|
||||||
|
@ -228,7 +228,7 @@ fn toom3_multiply_digit_array(operand_a []u32, operand_b []u32, mut storage []u3
|
|||||||
p2 := ((ptemp + a2).left_shift(1) - a0) * ((qtemp + b2).left_shift(1) - b0)
|
p2 := ((ptemp + a2).left_shift(1) - a0) * ((qtemp + b2).left_shift(1) - b0)
|
||||||
pinf := a2 * b2
|
pinf := a2 * b2
|
||||||
|
|
||||||
mut t2 := (p2 - vm1) / three_int
|
mut t2, _ := (p2 - vm1).div_mod_internal(three_int)
|
||||||
mut tm1 := (p1 - vm1).right_shift(1)
|
mut tm1 := (p1 - vm1).right_shift(1)
|
||||||
mut t1 := p1 - p0
|
mut t1 := p1 - p0
|
||||||
t2 = (t2 - t1).right_shift(1)
|
t2 = (t2 - t1).right_shift(1)
|
||||||
|
Loading…
Reference in New Issue
Block a user