123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- package math
- // pow returns x**y, the base-x exponential of y.
- //
- // Special cases are (in order):
- //
- // pow(x, ±0) = 1 for any x
- // pow(1, y) = 1 for any y
- // pow(x, 1) = x for any x
- // pow(NaN, y) = NaN
- // pow(x, NaN) = NaN
- // pow(±0, y) = ±Inf for y an odd integer < 0
- // pow(±0, -Inf) = +Inf
- // pow(±0, +Inf) = +0
- // pow(±0, y) = +Inf for finite y < 0 and not an odd integer
- // pow(±0, y) = ±0 for y an odd integer > 0
- // pow(±0, y) = +0 for finite y > 0 and not an odd integer
- // pow(-1, ±Inf) = 1
- // pow(x, +Inf) = +Inf for |x| > 1
- // pow(x, -Inf) = +0 for |x| > 1
- // pow(x, +Inf) = +0 for |x| < 1
- // pow(x, -Inf) = +Inf for |x| < 1
- // pow(+Inf, y) = +Inf for y > 0
- // pow(+Inf, y) = +0 for y < 0
- // pow(-Inf, y) = pow(-0, -y)
- // pow(x, y) = NaN for finite x < 0 and finite non-integer y
- //
- // Special cases taken from FreeBSD's /usr/src/lib/msun/src/e_pow.c
- // updated by IEEE Std. 754-2008 "Section 9.2.1 Special values".
- @(require_results)
- pow_f64 :: proc "contextless" (x, y: f64) -> f64 {
- is_odd_int :: proc "contextless" (x: f64) -> bool {
- if abs(x) >= (1<<53) {
- return false
- }
- i, f := modf(x)
- return f == 0 && (i64(i)&1 == 1)
- }
- switch {
- case y == 0 || x == 1:
- return 1.0
- case y == 1:
- return x
- case is_nan(x) || is_nan(y):
- return nan_f64()
- case x == 0:
- switch {
- case y < 0:
- if signbit(x) && is_odd_int(y) {
- return inf_f64(-1)
- }
- return inf_f64(1)
- case y > 0:
- if signbit(x) && is_odd_int(y) {
- return x
- }
- return 0.0
- }
- case is_inf(y, 0):
- switch {
- case x == -1:
- return 1.0
- case (abs(x) < 1) == is_inf(y, 1):
- return 0.0
- case:
- return inf_f64(1)
- }
- case is_inf(x, 0):
- if is_inf(x, -1) {
- // pow(-0, -y)
- return pow_f64(1.0/x, -y)
- }
- switch {
- case y < 0:
- return 0.0
- case y > 0:
- return inf_f64(1)
- }
- case y == 0.5:
- return sqrt_f64(x)
- case y == -0.5:
- return 1.0 / sqrt_f64(x)
- }
- yi, yf := modf(abs(y))
- if yf != 0 && x < 0 {
- return nan_f64()
- }
- if yi >= 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)
- switch {
- case x == -1:
- return 1.0
- case (abs(x) < 1) == (y > 0):
- return 0.0
- case:
- return inf_f64(1)
- }
- }
- // ans = a1 * 2**ae (= 1 for now).
- a1: f64 = 1
- ae: int = 0
- // ans *= x**yf
- if yf != 0 {
- if yf > 0.5 {
- yf -= 1
- yi += 1
- }
- a1 = exp(yf * ln(x))
- }
- // ans *= x**yi
- // by multiplying in successive squarings
- // of x according to bits of yi.
- // accumulate powers of two into exp.
- x1, xe := frexp(x)
- for i := i64(yi); i != 0; i >>= 1 {
- if xe < -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 f64 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 -= 1
- }
- }
- // 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)
- }
- @(require_results) pow_f16 :: proc "contextless" (x, power: f16) -> f16 { return f16(pow_f64(f64(x), f64(power))) }
- @(require_results) pow_f32 :: proc "contextless" (x, power: f32) -> f32 { return f32(pow_f64(f64(x), f64(power))) }
- exp_f64 :: proc "contextless" (x: f64) -> f64 {
- LN2_HI :: 6.93147180369123816490e-01
- LN2_LO :: 1.90821492927058770002e-10
- LOG2_E :: 1.44269504088896338700e+00
- OVERFLOW :: 7.09782712893383973096e+02
- UNDERFLOW :: -7.45133219101941108420e+02
- NEAR_ZERO :: 1.0 / (1 << 28) // 2**-28
- // special cases
- switch {
- case is_nan(x) || is_inf(x, 1):
- return x
- case is_inf(x, -1):
- return 0
- case x > OVERFLOW:
- return inf_f64(1)
- case x < UNDERFLOW:
- return 0
- case -NEAR_ZERO < x && x < NEAR_ZERO:
- return 1 + x
- }
- // reduce; computed as r = hi - lo for extra precision.
- k: int
- switch {
- case x < 0:
- k = int(LOG2_E*x - 0.5)
- case x > 0:
- k = int(LOG2_E*x + 0.5)
- }
- hi := x - f64(k)*LN2_HI
- lo := f64(k) * LN2_LO
- P1 :: 0h3FC5555555555555 // 1.66666666666666657415e-01
- P2 :: 0hBF66C16C16BEBD93 // -2.77777777770155933842e-03
- P3 :: 0h3F11566AAF25DE2C // 6.61375632143793436117e-05
- P4 :: 0hBEBBBD41C5D26BF1 // -1.65339022054652515390e-06
- P5 :: 0h3E66376972BEA4D0 // 4.13813679705723846039e-08
- r := hi - lo
- t := r * r
- c := r - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))))
- y := 1 - ((lo - (r*c)/(2-c)) - hi)
- return ldexp(y, k)
- }
- @(require_results) exp_f16 :: proc "contextless" (x: f16) -> f16 { return f16(exp_f64(f64(x))) }
- @(require_results) exp_f32 :: proc "contextless" (x: f32) -> f32 { return f32(exp_f64(f64(x))) }
|