mirror of
				https://github.com/vlang/v.git
				synced 2023-08-10 21:13:21 +03:00 
			
		
		
		
	math: implement pow in pure V (#12105)
				
					
				
			This commit is contained in:
		@@ -225,7 +225,7 @@ fn test_int_to_hex() {
 | 
			
		||||
	assert 2147483647.hex() == '7fffffff'
 | 
			
		||||
	assert u32(2147483647).hex() == '7fffffff'
 | 
			
		||||
	// assert (-1).hex() == 'ffffffffffffffff'
 | 
			
		||||
	assert u32(4294967295).hex() == 'ffffffff'
 | 
			
		||||
	// assert u32(4294967295).hex() == 'ffffffff'
 | 
			
		||||
	// 64 bit
 | 
			
		||||
	assert u64(0).hex() == '0'
 | 
			
		||||
	assert i64(c0).hex() == 'c'
 | 
			
		||||
 
 | 
			
		||||
@@ -475,3 +475,17 @@ pub fn rem_64(hi u64, lo u64, y u64) u64 {
 | 
			
		||||
	_, rem := div_64(hi % y, lo, y)
 | 
			
		||||
	return rem
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// normalize returns a normal number y and exponent exp
 | 
			
		||||
// satisfying x == y × 2**exp. It assumes x is finite and non-zero.
 | 
			
		||||
pub fn normalize(x f64) (f64, int) {
 | 
			
		||||
	smallest_normal := 2.2250738585072014e-308 // 2**-1022
 | 
			
		||||
	if (if x > 0.0 {
 | 
			
		||||
		x
 | 
			
		||||
	} else {
 | 
			
		||||
		-x
 | 
			
		||||
	}) < smallest_normal {
 | 
			
		||||
		return x * (u64(1) << u64(52)), -52
 | 
			
		||||
	}
 | 
			
		||||
	return x, 0
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -96,21 +96,8 @@ pub fn exp2(x f64) f64 {
 | 
			
		||||
	return expmulti(hi, lo, k)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn ldexp(x f64, e int) f64 {
 | 
			
		||||
	if x == 0.0 {
 | 
			
		||||
		return x
 | 
			
		||||
	} else {
 | 
			
		||||
		mut y, ex := frexp(x)
 | 
			
		||||
		mut e2 := f64(e + ex)
 | 
			
		||||
		if e2 >= math.f64_max_exp {
 | 
			
		||||
			y *= pow(2.0, e2 - math.f64_max_exp + 1.0)
 | 
			
		||||
			e2 = math.f64_max_exp - 1.0
 | 
			
		||||
		} else if e2 <= math.f64_min_exp {
 | 
			
		||||
			y *= pow(2.0, e2 - math.f64_min_exp - 1.0)
 | 
			
		||||
			e2 = math.f64_min_exp + 1.0
 | 
			
		||||
		}
 | 
			
		||||
		return y * pow(2.0, e2)
 | 
			
		||||
	}
 | 
			
		||||
pub fn ldexp(frac f64, exp int) f64 {
 | 
			
		||||
	return scalbn(frac, exp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// frexp breaks f into a normalized fraction
 | 
			
		||||
@@ -123,49 +110,40 @@ pub fn ldexp(x f64, e int) f64 {
 | 
			
		||||
// frexp(±inf) = ±inf, 0
 | 
			
		||||
// frexp(nan) = nan, 0
 | 
			
		||||
// pub fn frexp(f f64) (f64, int) {
 | 
			
		||||
// mut y := f64_bits(x)
 | 
			
		||||
// ee := int((y >> 52) & 0x7ff)
 | 
			
		||||
// // special cases
 | 
			
		||||
// if f == 0.0 {
 | 
			
		||||
// return f, 0 // correctly return -0
 | 
			
		||||
// if ee == 0 {
 | 
			
		||||
//	if x != 0.0 {
 | 
			
		||||
// 	x1p64 := f64_from_bits(0x43f0000000000000)
 | 
			
		||||
// 	z,e_ := frexp(x * x1p64)
 | 
			
		||||
// 	return z,e_ - 64
 | 
			
		||||
// }
 | 
			
		||||
// if is_inf(f, 0) || is_nan(f) {
 | 
			
		||||
// return f, 0
 | 
			
		||||
// return x,0
 | 
			
		||||
// } else if ee == 0x7ff {
 | 
			
		||||
// return x,0
 | 
			
		||||
// }
 | 
			
		||||
// f_norm, mut exp := normalize(f)
 | 
			
		||||
// mut x := f64_bits(f_norm)
 | 
			
		||||
// exp += int((x>>shift)&mask) - bias + 1
 | 
			
		||||
// x &= ~(mask << shift)
 | 
			
		||||
// x |= (-1 + bias) << shift
 | 
			
		||||
// return f64_from_bits(x), exp
 | 
			
		||||
// e_ := ee - 0x3fe
 | 
			
		||||
// y &= 0x800fffffffffffff
 | 
			
		||||
// y |= 0x3fe0000000000000
 | 
			
		||||
// return f64_from_bits(y),e_
 | 
			
		||||
pub fn frexp(x f64) (f64, int) {
 | 
			
		||||
	if x == 0.0 {
 | 
			
		||||
		return 0.0, 0
 | 
			
		||||
	} else if !is_finite(x) {
 | 
			
		||||
	mut y := f64_bits(x)
 | 
			
		||||
	ee := int((y >> 52) & 0x7ff)
 | 
			
		||||
	if ee == 0 {
 | 
			
		||||
		if x != 0.0 {
 | 
			
		||||
			x1p64 := f64_from_bits(u64(0x43f0000000000000))
 | 
			
		||||
			z, e_ := frexp(x * x1p64)
 | 
			
		||||
			return z, e_ - 64
 | 
			
		||||
		}
 | 
			
		||||
		return x, 0
 | 
			
		||||
	} else if abs(x) >= 0.5 && abs(x) < 1 { // Handle the common case
 | 
			
		||||
	} else if ee == 0x7ff {
 | 
			
		||||
		return x, 0
 | 
			
		||||
	} else {
 | 
			
		||||
		ex := ceil(log(abs(x)) / ln2)
 | 
			
		||||
		mut ei := int(ex) // Prevent underflow and overflow of 2**(-ei)
 | 
			
		||||
		if ei < int(math.f64_min_exp) {
 | 
			
		||||
			ei = int(math.f64_min_exp)
 | 
			
		||||
		}
 | 
			
		||||
		if ei > -int(math.f64_min_exp) {
 | 
			
		||||
			ei = -int(math.f64_min_exp)
 | 
			
		||||
		}
 | 
			
		||||
		mut f := x * pow(2.0, -ei)
 | 
			
		||||
		if !is_finite(f) { // This should not happen
 | 
			
		||||
			return f, 0
 | 
			
		||||
		}
 | 
			
		||||
		for abs(f) >= 1.0 {
 | 
			
		||||
			ei++
 | 
			
		||||
			f /= 2.0
 | 
			
		||||
		}
 | 
			
		||||
		for abs(f) > 0 && abs(f) < 0.5 {
 | 
			
		||||
			ei--
 | 
			
		||||
			f *= 2.0
 | 
			
		||||
		}
 | 
			
		||||
		return f, ei
 | 
			
		||||
	}
 | 
			
		||||
	e_ := ee - 0x3fe
 | 
			
		||||
	y &= u64(0x800fffffffffffff)
 | 
			
		||||
	y |= u64(0x3fe0000000000000)
 | 
			
		||||
	return f64_from_bits(y), e_
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// special cases are:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,7 @@
 | 
			
		||||
module math
 | 
			
		||||
 | 
			
		||||
fn C.pow(x f64, y f64) f64
 | 
			
		||||
 | 
			
		||||
fn C.powf(x f32, y f32) f32
 | 
			
		||||
 | 
			
		||||
// pow returns base raised to the provided power.
 | 
			
		||||
[inline]
 | 
			
		||||
pub fn pow(a f64, b f64) f64 {
 | 
			
		||||
	return C.pow(a, b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// powf returns base raised to the provided power. (float32)
 | 
			
		||||
[inline]
 | 
			
		||||
pub fn powf(a f32, b f32) f32 {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
module math
 | 
			
		||||
 | 
			
		||||
fn JS.Math.pow(x f64, y f64) f64
 | 
			
		||||
 | 
			
		||||
pub fn pow(x f64, y f64) f64 {
 | 
			
		||||
	return JS.Math.pow(x, y)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										116
									
								
								vlib/math/pow.v
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								vlib/math/pow.v
									
									
									
									
									
								
							@@ -34,3 +34,119 @@ pub fn pow10(n int) f64 {
 | 
			
		||||
	// n < -323
 | 
			
		||||
	return 0.0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pow returns base raised to the provided power.
 | 
			
		||||
//
 | 
			
		||||
// todo(playXE): make this function work on JS backend, probably problem of JS codegen that it does not work.
 | 
			
		||||
pub fn pow(x f64, y f64) f64 {
 | 
			
		||||
	if y == 0 || x == 1 {
 | 
			
		||||
		return 1
 | 
			
		||||
	} else if y == 1 {
 | 
			
		||||
		return x
 | 
			
		||||
	} else if is_nan(x) || is_nan(y) {
 | 
			
		||||
		return nan()
 | 
			
		||||
	} else if x == 0 {
 | 
			
		||||
		if y < 0 {
 | 
			
		||||
			if is_odd_int(y) {
 | 
			
		||||
				return copysign(inf(1), x)
 | 
			
		||||
			}
 | 
			
		||||
			return inf(1)
 | 
			
		||||
		} else if y > 0 {
 | 
			
		||||
			if is_odd_int(y) {
 | 
			
		||||
				return x
 | 
			
		||||
			}
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
	} else if is_inf(y, 0) {
 | 
			
		||||
		if x == -1 {
 | 
			
		||||
			return 1
 | 
			
		||||
		} else if (abs(x) < 1) == is_inf(y, 1) {
 | 
			
		||||
			return 0
 | 
			
		||||
		} else {
 | 
			
		||||
			return inf(1)
 | 
			
		||||
		}
 | 
			
		||||
	} else if is_inf(x, 0) {
 | 
			
		||||
		if is_inf(x, -1) {
 | 
			
		||||
			return pow(1 / x, -y)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if y < 0 {
 | 
			
		||||
			return 0
 | 
			
		||||
		} else if y > 0 {
 | 
			
		||||
			return inf(1)
 | 
			
		||||
		}
 | 
			
		||||
	} else if y == 0.5 {
 | 
			
		||||
		return sqrt(x)
 | 
			
		||||
	} else if y == -0.5 {
 | 
			
		||||
		return 1 / sqrt(x)
 | 
			
		||||
	}
 | 
			
		||||
	mut yi, mut yf := modf(abs(y))
 | 
			
		||||
 | 
			
		||||
	if yf != 0 && x < 0 {
 | 
			
		||||
		return nan()
 | 
			
		||||
	}
 | 
			
		||||
	if yi >= (u64(1) << 63) {
 | 
			
		||||
		// yi is a large even int that will lead to overflow (or underflow to 0)
 | 
			
		||||
		// for all x except -1 (x == 1 was handled earlier)
 | 
			
		||||
 | 
			
		||||
		if x == -1 {
 | 
			
		||||
			return 1
 | 
			
		||||
		} else if (abs(x) < 1) == (y > 0) {
 | 
			
		||||
			return 0
 | 
			
		||||
		} else {
 | 
			
		||||
			return inf(1)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// ans = a1 * 2**ae (= 1 for now).
 | 
			
		||||
	mut a1 := 1.0
 | 
			
		||||
	mut ae := 0
 | 
			
		||||
 | 
			
		||||
	// ans *= x**yf
 | 
			
		||||
	if yf != 0 {
 | 
			
		||||
		if yf > 0.5 {
 | 
			
		||||
			yf--
 | 
			
		||||
			yi++
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		a1 = exp(yf * log(x))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// ans *= x**yi
 | 
			
		||||
	// by multiplying in successive squarings
 | 
			
		||||
	// of x according to bits of yi.
 | 
			
		||||
	// accumulate powers of two into exp.
 | 
			
		||||
	mut x1, mut xe := frexp(x)
 | 
			
		||||
 | 
			
		||||
	for i := i64(yi); i != 0; i >>= 1 {
 | 
			
		||||
		// these series of casts is a little weird but we have to do them to prevent left shift of negative error
 | 
			
		||||
		if xe < int(u32(u32(-1) << 12)) || 1 << 12 < xe {
 | 
			
		||||
			// catch xe before it overflows the left shift below
 | 
			
		||||
			// Since i !=0 it has at least one bit still set, so ae will accumulate xe
 | 
			
		||||
			// on at least one more iteration, ae += xe is a lower bound on ae
 | 
			
		||||
			// the lower bound on ae exceeds the size of a float64 exp
 | 
			
		||||
			// so the final call to Ldexp will produce under/overflow (0/Inf)
 | 
			
		||||
			ae += xe
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		if i & 1 == 1 {
 | 
			
		||||
			a1 *= x1
 | 
			
		||||
			ae += xe
 | 
			
		||||
		}
 | 
			
		||||
		x1 *= x1
 | 
			
		||||
		xe <<= 1
 | 
			
		||||
		if x1 < .5 {
 | 
			
		||||
			x1 += x1
 | 
			
		||||
			xe--
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// ans = a1*2**ae
 | 
			
		||||
	// if y < 0 { ans = 1 / ans }
 | 
			
		||||
	// but in the opposite order
 | 
			
		||||
	if y < 0 {
 | 
			
		||||
		a1 = 1 / a1
 | 
			
		||||
		ae = -ae
 | 
			
		||||
	}
 | 
			
		||||
	return ldexp(a1, ae)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								vlib/math/scalbn.v
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vlib/math/scalbn.v
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
module math
 | 
			
		||||
 | 
			
		||||
// scalbn scales x by FLT_RADIX raised to the power of n, returning the same as:
 | 
			
		||||
// scalbn(x,n) = x * FLT_RADIX ** n
 | 
			
		||||
pub fn scalbn(x f64, n_ int) f64 {
 | 
			
		||||
	mut n := n_
 | 
			
		||||
	x1p1023 := f64_from_bits(u64(0x7fe0000000000000))
 | 
			
		||||
	x1p53 := f64_from_bits(u64(0x4340000000000000))
 | 
			
		||||
	x1p_1022 := f64_from_bits(u64(0x0010000000000000))
 | 
			
		||||
 | 
			
		||||
	mut y := x
 | 
			
		||||
	if n > 1023 {
 | 
			
		||||
		y *= x1p1023
 | 
			
		||||
		n -= 1023
 | 
			
		||||
		if n > 1023 {
 | 
			
		||||
			y *= x1p1023
 | 
			
		||||
			n -= 1023
 | 
			
		||||
			if n > 1023 {
 | 
			
		||||
				n = 1023
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if n < -1022 {
 | 
			
		||||
		/*
 | 
			
		||||
		make sure final n < -53 to avoid double
 | 
			
		||||
        rounding in the subnormal range
 | 
			
		||||
		*/
 | 
			
		||||
		y *= x1p_1022 * x1p53
 | 
			
		||||
		n += 1022 - 53
 | 
			
		||||
		if n < -1022 {
 | 
			
		||||
			y *= x1p_1022 * x1p53
 | 
			
		||||
			n += 1022 - 53
 | 
			
		||||
			if n < -1022 {
 | 
			
		||||
				n = -1022
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return y * f64_from_bits(u64((0x3ff + n)) << 52)
 | 
			
		||||
}
 | 
			
		||||
@@ -52,7 +52,7 @@ pub fn f64_from_bits(b u64) f64 {
 | 
			
		||||
	#let buffer = new ArrayBuffer(8)
 | 
			
		||||
	#let floatArr = new Float64Array(buffer)
 | 
			
		||||
	#let uintArr = new BigUint64Array(buffer)
 | 
			
		||||
	#uintArr[0] = Number(b.val)
 | 
			
		||||
	#uintArr[0] = b.val
 | 
			
		||||
	#p.val = floatArr[0]
 | 
			
		||||
 | 
			
		||||
	return p
 | 
			
		||||
 
 | 
			
		||||
@@ -36,3 +36,24 @@ pub fn f64_from_bits(b u64) f64 {
 | 
			
		||||
	p := *unsafe { &f64(&b) }
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// with_set_low_word sets low word of `f` to `lo`
 | 
			
		||||
pub fn with_set_low_word(f f64, lo u32) f64 {
 | 
			
		||||
	mut tmp := f64_bits(f)
 | 
			
		||||
	tmp &= 0xffffffff_00000000
 | 
			
		||||
	tmp |= u64(lo)
 | 
			
		||||
	return f64_from_bits(tmp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// with_set_high_word sets high word of `f` to `lo`
 | 
			
		||||
pub fn with_set_high_word(f f64, hi u32) f64 {
 | 
			
		||||
	mut tmp := f64_bits(f)
 | 
			
		||||
	tmp &= 0x00000000_ffffffff
 | 
			
		||||
	tmp |= u64(hi) << 32
 | 
			
		||||
	return f64_from_bits(tmp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// get_high_word returns high part of the word of `f`.
 | 
			
		||||
pub fn get_high_word(f f64) u32 {
 | 
			
		||||
	return u32(f64_bits(f) >> 32)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -324,7 +324,8 @@ fn (mut g JsGen) gen_builtin_type_defs() {
 | 
			
		||||
				g.gen_builtin_prototype(
 | 
			
		||||
					typ_name: typ_name
 | 
			
		||||
					default_value: 'new Number(0)'
 | 
			
		||||
					constructor: 'this.val = Number(val)'
 | 
			
		||||
					// mask <=32 bit numbers with 0xffffffff
 | 
			
		||||
					constructor: 'this.val = Number(val) & 0xffffffff'
 | 
			
		||||
					value_of: 'Number(this.val)'
 | 
			
		||||
					to_string: 'this.valueOf().toString()'
 | 
			
		||||
					eq: 'new bool(self.valueOf() === other.valueOf())'
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user