aboutsummaryrefslogtreecommitdiff
path: root/core/math
diff options
context:
space:
mode:
authorJuan Ignacio Díaz <diazjignacio@gmail.com>2024-02-16 13:11:49 -0300
committerJuan Ignacio Díaz <diazjignacio@gmail.com>2024-02-16 13:23:44 -0300
commit7a592cbb31f351627e7d508de9fafacfa65404cc (patch)
treea5d68c4e1e7b8904f39e6003c8d293b4ad602ba4 /core/math
parentc5c2a4d09d98f0d3b6263e204785553e47b83395 (diff)
port math.round from Golang
Diffstat (limited to 'core/math')
-rw-r--r--core/math/math.odin103
1 files changed, 73 insertions, 30 deletions
diff --git a/core/math/math.odin b/core/math/math.odin
index 7fdbcba04..982f4b984 100644
--- a/core/math/math.odin
+++ b/core/math/math.odin
@@ -644,42 +644,85 @@ trunc :: proc{
}
@(require_results)
-round_f16 :: proc "contextless" (x: f16) -> f16 {
- return ceil(x - 0.5) if x < 0 else floor(x + 0.5)
-}
-@(require_results)
-round_f16le :: proc "contextless" (x: f16le) -> f16le {
- return ceil(x - 0.5) if x < 0 else floor(x + 0.5)
-}
-@(require_results)
-round_f16be :: proc "contextless" (x: f16be) -> f16be {
- return ceil(x - 0.5) if x < 0 else floor(x + 0.5)
-}
+round_f16 :: proc "contextless" (x: f16) -> f16 {
+ mask :: F16_MASK
+ shift :: F16_SHIFT
+ bias :: F16_BIAS
-@(require_results)
-round_f32 :: proc "contextless" (x: f32) -> f32 {
- return ceil(x - 0.5) if x < 0 else floor(x + 0.5)
-}
-@(require_results)
-round_f32le :: proc "contextless" (x: f32le) -> f32le {
- return ceil(x - 0.5) if x < 0 else floor(x + 0.5)
-}
-@(require_results)
-round_f32be :: proc "contextless" (x: f32be) -> f32be {
- return ceil(x - 0.5) if x < 0 else floor(x + 0.5)
-}
-@(require_results)
-round_f64 :: proc "contextless" (x: f64) -> f64 {
- return ceil(x - 0.5) if x < 0 else floor(x + 0.5)
+ bits := transmute(u16)x
+ e := (bits >> shift) & mask
+
+ if e < bias {
+ bits &= 0x8000
+ if e == bias - 1 {
+ bits |= transmute(u16)f16(1)
+ }
+ } else if e < bias + shift {
+ half :: 1 << (shift - 1)
+ mantissa :: (1 << shift) - 1
+ e -= bias
+ bits += half >> e
+ bits &~= mantissa >> e
+ }
+
+ return transmute(f16)bits
}
+@(require_results) round_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(round_f16(f16(x))) }
+@(require_results) round_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(round_f16(f16(x))) }
+
@(require_results)
-round_f64le :: proc "contextless" (x: f64le) -> f64le {
- return ceil(x - 0.5) if x < 0 else floor(x + 0.5)
+round_f32 :: proc "contextless" (x: f32) -> f32 {
+ mask :: F32_MASK
+ shift :: F32_SHIFT
+ bias :: F32_BIAS
+
+ bits := transmute(u32)x
+ e := (bits >> shift) & mask
+
+ if e < bias {
+ bits &= 0x8000_0000
+ if e == bias - 1 {
+ bits |= transmute(u32)f32(1)
+ }
+ } else if e < bias + shift {
+ half :: 1 << (shift - 1)
+ mantissa :: (1 << shift) - 1
+ e -= bias
+ bits += half >> e
+ bits &~= mantissa >> e
+ }
+
+ return transmute(f32)bits
}
+@(require_results) round_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(round_f32(f32(x))) }
+@(require_results) round_f32be :: proc "contextless" (x: f32be) -> f32be { return #force_inline f32be(round_f32(f32(x))) }
+
@(require_results)
-round_f64be :: proc "contextless" (x: f64be) -> f64be {
- return ceil(x - 0.5) if x < 0 else floor(x + 0.5)
+round_f64 :: proc "contextless" (x: f64) -> f64 {
+ mask :: F64_MASK
+ shift :: F64_SHIFT
+ bias :: F64_BIAS
+
+ bits := transmute(u64)x
+ e := (bits >> shift) & mask
+
+ if e < bias {
+ bits &= 0x8000_0000_0000_0000
+ if e == bias - 1 {
+ bits |= transmute(u64)f64(1)
+ }
+ } else if e < bias + shift {
+ half :: 1 << (shift - 1)
+ mantissa :: (1 << shift) - 1
+ e -= bias
+ bits += half >> e
+ bits &~= mantissa >> e
+ }
+
+ return transmute(f64)bits
}
+@(require_results) round_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(round_f64(f64(x))) }
+@(require_results) round_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(round_f64(f64(x))) }
round :: proc{
round_f16, round_f16le, round_f16be,
round_f32, round_f32le, round_f32be,