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 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() {
|
||||
|
@ -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`.
|
||||
pub fn (dividend Integer) div_mod(divisor Integer) (Integer, Integer) {
|
||||
// Quick exits
|
||||
if divisor.signum == 0 {
|
||||
panic('Cannot divide by zero')
|
||||
// div_mod_internal is an entirely unchecked (in terms of division by zero) method for division.
|
||||
// This should only be used for internal calculations involving a definitive non-zero
|
||||
// divisor.
|
||||
//
|
||||
// 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 {
|
||||
return zero_int, zero_int
|
||||
}
|
||||
@ -382,11 +386,11 @@ pub fn (dividend Integer) div_mod(divisor Integer) (Integer, Integer) {
|
||||
return dividend.clone(), zero_int
|
||||
}
|
||||
if divisor.signum == -1 {
|
||||
q, r := dividend.div_mod(divisor.neg())
|
||||
q, r := dividend.div_mod_internal(divisor.neg())
|
||||
return q.neg(), r
|
||||
}
|
||||
if dividend.signum == -1 {
|
||||
q, r := dividend.neg().div_mod(divisor)
|
||||
q, r := dividend.neg().div_mod_internal(divisor)
|
||||
if r.signum == 0 {
|
||||
return q.neg(), zero_int
|
||||
} else {
|
||||
@ -408,18 +412,64 @@ pub fn (dividend Integer) div_mod(divisor Integer) (Integer, Integer) {
|
||||
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`.
|
||||
//
|
||||
// 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 {
|
||||
q, _ := dividend.div_mod(divisor)
|
||||
return q
|
||||
}
|
||||
|
||||
// % 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 {
|
||||
_, r := dividend.div_mod(divisor)
|
||||
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
|
||||
// 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.
|
||||
@ -791,7 +841,7 @@ pub fn (integer Integer) hex() string {
|
||||
|
||||
// radix_str returns the string representation of the integer `a` in the specified radix.
|
||||
pub fn (integer Integer) radix_str(radix u32) string {
|
||||
if integer.signum == 0 {
|
||||
if integer.signum == 0 || radix == 0 {
|
||||
return '0'
|
||||
}
|
||||
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 {
|
||||
$if debug {
|
||||
assert radix != 0
|
||||
}
|
||||
divisor := integer_from_u32(radix)
|
||||
|
||||
mut current := integer.abs()
|
||||
@ -815,7 +868,7 @@ fn (integer Integer) general_radix_str(radix u32) string {
|
||||
mut digit := zero_int
|
||||
mut rune_array := []rune{cap: current.digits.len * 4}
|
||||
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()]
|
||||
unsafe { digit.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() {
|
||||
one_int, n - b
|
||||
} else {
|
||||
n.div_mod(b)
|
||||
// safe because the loop terminates if b == 0
|
||||
n.div_mod_internal(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)
|
||||
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 t1 := p1 - p0
|
||||
t2 = (t2 - t1).right_shift(1)
|
||||
|
Loading…
Reference in New Issue
Block a user