Add math.cbrt

Based on the https://www.netlib.org/fdlibm/s_cbrt.c
This commit is contained in:
gingerBill
2026-05-27 10:37:21 +01:00
parent d0fc43bd12
commit db512cd83a

103
core/math/cbrt.odin Normal file
View File

@@ -0,0 +1,103 @@
package math
import "base:intrinsics"
@(require_results) cbrt_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(cbrt_f16(f16(x))) }
@(require_results) cbrt_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(cbrt_f16(f16(x))) }
@(require_results) cbrt_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(cbrt_f32(f32(x))) }
@(require_results) cbrt_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(cbrt_f32(f32(x))) }
@(require_results) cbrt_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(cbrt_f64(f64(x))) }
@(require_results) cbrt_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(cbrt_f64(f64(x))) }
// cbrt returns the cube root of x.
//
// Special cases are:
//
// cbrt(±0) = ±0
// cbrt(±Inf) = ±Inf
// cbrt(NaN) = NaN
cbrt :: proc{
cbrt_f16, cbrt_f16le, cbrt_f16be,
cbrt_f32, cbrt_f32le, cbrt_f32be,
cbrt_f64, cbrt_f64le, cbrt_f64be,
}
@(require_results)
cbrt_f16 :: proc "contextless" (x: f16) -> f16 { return #force_inline f16(cbrt_f64(f64(x))) }
@(require_results)
cbrt_f32 :: proc "contextless" (x: f32) -> f32 { return #force_inline f32(cbrt_f64(f64(x))) }
// cbrt returns the cube root of x.
//
// Special cases are:
//
// cbrt(±0) = ±0
// cbrt(±Inf) = ±Inf
// cbrt(NaN) = NaN
@(require_results)
cbrt_f64 :: proc "contextless" (x: f64) -> f64 {
// http://www.netlib.org/fdlibm/s_cbrt.c and came with this notice.
//
// ====================================================
// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
//
// Developed at SunSoft, a Sun Microsystems, Inc. business.
// Permission to use, copy, modify, and distribute this
// software is freely granted, provided that this notice
// is preserved.
// ====================================================
B1 :: 715094163 // (682-0.03306235651)*2**20
B2 :: 696219795 // (664-0.03306235651)*2**20
SMALLEST_NORMAL :: 0h0010000000000000 // 2.22507385850720138309e-308 == 2**-1022
C :: 0h3FE15F15F15F15F1 // 5.42857142857142815906e-01 == 19/35
D :: 0hBFE691DE2532C834 // -7.05306122448979611050e-01 == -864/1225
E :: 0h3FF6A0EA0EA0EA0F // 1.41428571428571436819e+00 == 99/70
F :: 0h3FF9B6DB6DB6DB6E // 1.60714285714285720630e+00 == 45/28
G :: 0h3FD6DB6DB6DB6DB7 // 3.57142857142857150787e-01 == 5/14
x := x
switch {
case x == 0 || is_nan(x) || is_inf(x, 0):
return x
}
sign := false
if x < 0 {
x = -x
sign = true
}
// Approximate cbrt (5-bits)
t := transmute(f64)((transmute(u64)x)/3 + B1<<32)
if x < SMALLEST_NORMAL {
t = f64(1 << 54)
t *= x
t = transmute(f64)((transmute(u64)x)/3 + B2<<32)
}
// Approximate cbrt (23-bits)
r := t * t / x
s := C + r*t
t *= G + F/(s+E + D/s)
// Truncate to 22 bits, make larger than cbrt(x)
t = transmute(f64)((transmute(u64)t)&(0xffffffffc<<28) + 1<<30)
// Single step of Newton-Raphson iteration to 53 bits with error less than 0.667ulps
s = t * t // t*t is exact
r = x / s
w := t + t
r = (r - t) / (w + r) // r-s is exact
t = t + t*r
// Restore sign
if sign {
t = -t
}
return t
}