math: use Trunc to implement Modf

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>
This commit is contained in:
Michael Munday 2025-07-29 00:30:04 +01:00
parent 4e05a070c4
commit 25c2d4109f
6 changed files with 13 additions and 90 deletions

View 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.

View 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
}

View file

@ -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

View file

@ -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)

View file

@ -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")
}

View file

@ -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