]> Cypherpunks repositories - gostls13.git/commitdiff
math: use Trunc to implement Modf
authorMichael Munday <mndygolang+git@gmail.com>
Mon, 28 Jul 2025 23:30:04 +0000 (00:30 +0100)
committerMichael Munday <mndygolang+git@gmail.com>
Mon, 25 Aug 2025 19:46:11 +0000 (12:46 -0700)
By implementing Modf using Trunc, rather than the other way round,
we can get a significant performance improvement on platforms where
Trunc is implemented as an intrinsic.

Trunc is implemented as an intrinsic on ppc64x and arm64 so the assembly
implementations of Modf are no longer needed (the compiler can generate
very similar code that can now potentially be inlined).

GOAMD64=v1

goos: linux
goarch: amd64
pkg: math
cpu: 12th Gen Intel(R) Core(TM) i7-12700T
        │       sec/op       │    sec/op     vs base                │
Gamma            4.257n ± 0%    3.890n ± 0%   -8.61% (p=0.000 n=10)
Modf            1.6110n ± 0%   0.4243n ± 0%  -73.67% (p=0.000 n=10)
geomean          2.619n         1.285n       -50.94%

GOAMD64=v2

goos: linux
goarch: amd64
pkg: math
cpu: 12th Gen Intel(R) Core(TM) i7-12700T
        │       sec/op       │    sec/op     vs base                │
Gamma            4.100n ± 1%    3.717n ± 0%   -9.35% (p=0.000 n=10)
Modf            1.6070n ± 0%   0.2158n ± 1%  -86.57% (p=0.000 n=10)
geomean          2.567n        0.8957n       -65.11%

Change-Id: I689a560c344cf1d39ef002b540749bacc3179786
Reviewed-on: https://go-review.googlesource.com/c/go/+/694896
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Sean Liao <sean@liao.dev>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Keith Randall <khr@google.com>
src/math/floor.go
src/math/modf.go
src/math/modf_arm64.s [deleted file]
src/math/modf_asm.go [deleted file]
src/math/modf_noasm.go [deleted file]
src/math/modf_ppc64x.s [deleted file]

index cb5856424b4e76a7cbbbec04a3551365d6aa9ca9..20a764112478c8713157ea63703dab451f367873 100644 (file)
@@ -66,11 +66,18 @@ func Trunc(x float64) float64 {
 }
 
 func trunc(x float64) float64 {
-       if x == 0 || IsNaN(x) || IsInf(x, 0) {
-               return x
+       if Abs(x) < 1 {
+               return Copysign(0, x)
        }
-       d, _ := Modf(x)
-       return d
+
+       b := Float64bits(x)
+       e := uint(b>>shift)&mask - bias
+
+       // Keep the top 12+e bits, the integer part; clear the rest.
+       if e < 64-12 {
+               b &^= 1<<(64-12-e) - 1
+       }
+       return Float64frombits(b)
 }
 
 // Round returns the nearest integer, rounding half away from zero.
index 613a75fc9a6864d47902a57ed5663c78a8e5c5c0..ab73e2dc36831eb25630326b9ca7ab883dbbde0b 100644 (file)
@@ -12,32 +12,7 @@ package math
 //     Modf(±Inf) = ±Inf, NaN
 //     Modf(NaN) = NaN, NaN
 func Modf(f float64) (int float64, frac float64) {
-       if haveArchModf {
-               return archModf(f)
-       }
-       return modf(f)
-}
-
-func modf(f float64) (int float64, frac float64) {
-       if f < 1 {
-               switch {
-               case f < 0:
-                       int, frac = Modf(-f)
-                       return -int, -frac
-               case f == 0:
-                       return f, f // Return -0, -0 when f == -0
-               }
-               return 0, f
-       }
-
-       x := Float64bits(f)
-       e := uint(x>>shift)&mask - bias
-
-       // Keep the top 12+e bits, the integer part; clear the rest.
-       if e < 64-12 {
-               x &^= 1<<(64-12-e) - 1
-       }
-       int = Float64frombits(x)
-       frac = f - int
+       int = Trunc(f)
+       frac = Copysign(f-int, f)
        return
 }
diff --git a/src/math/modf_arm64.s b/src/math/modf_arm64.s
deleted file mode 100644 (file)
index 1e4a329..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "textflag.h"
-
-// func archModf(f float64) (int float64, frac float64)
-TEXT ·archModf(SB),NOSPLIT,$0
-       MOVD    f+0(FP), R0
-       FMOVD   R0, F0
-       FRINTZD F0, F1
-       FMOVD   F1, int+8(FP)
-       FSUBD   F1, F0
-       FMOVD   F0, R1
-       AND     $(1<<63), R0
-       ORR     R0, R1 // must have same sign
-       MOVD    R1, frac+16(FP)
-       RET
diff --git a/src/math/modf_asm.go b/src/math/modf_asm.go
deleted file mode 100644 (file)
index c63be6c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build arm64 || ppc64 || ppc64le
-
-package math
-
-const haveArchModf = true
-
-func archModf(f float64) (int float64, frac float64)
diff --git a/src/math/modf_noasm.go b/src/math/modf_noasm.go
deleted file mode 100644 (file)
index 55c6a7f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !arm64 && !ppc64 && !ppc64le
-
-package math
-
-const haveArchModf = false
-
-func archModf(f float64) (int float64, frac float64) {
-       panic("not implemented")
-}
diff --git a/src/math/modf_ppc64x.s b/src/math/modf_ppc64x.s
deleted file mode 100644 (file)
index 410b523..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build ppc64 || ppc64le
-
-#include "textflag.h"
-
-// func archModf(f float64) (int float64, frac float64)
-TEXT ·archModf(SB),NOSPLIT,$0
-       FMOVD   f+0(FP), F0
-       FRIZ    F0, F1
-       FMOVD   F1, int+8(FP)
-       FSUB    F1, F0, F2
-       FCPSGN  F2, F0, F2
-       FMOVD   F2, frac+16(FP)
-       RET