Go 1.10 wurde freigegeben und fügt eine math.Round()
Funktion hinzu. Diese Funktion rundet auf die nächste ganze Zahl (die im Grunde ein „round zur nächsten 1.0“ Betrieb), und die Verwendung dieser wir sehr leicht eine Funktion konstruieren kann, die an das Gerät unserer Wahl Runden:
func Round(x, unit float64) float64 {
return math.Round(x/unit) * unit
}
Testing es:
fmt.Println(Round(0.363636, 0.05)) // 0.35
fmt.Println(Round(3.232, 0.05)) // 3.25
fmt.Println(Round(0.4888, 0.05)) // 0.5
fmt.Println(Round(-0.363636, 0.05)) // -0.35
fmt.Println(Round(-3.232, 0.05)) // -3.25
fmt.Println(Round(-0.4888, 0.05)) // -0.5
Versuchen sie es auf dem Go Playground.
Die ursprüngliche Antwort folgt, die in der Ära erstellt wurde, in der keine math.Round()
existiert, und die auch die Logik hinter unserer benutzerdefinierten Round()
-Funktion detailliert. Es ist hier für Bildungszwecke.
In der Pre-Go1.10 Ära gab es keine math.Round()
. Aber ...
Rounding Aufgaben können leicht durch eine float64
=>int64
converison umgesetzt werden, sondern muss darauf geachtet werden, wie Schwimmer genommen wird Umwandlung in int wird nicht Rundung aber hält den ganzzahligen Teil (siehe Details in Go: Converting float64 to int with multiplier).
Zum Beispiel:
var f float64
f = 12.3
fmt.Println(int64(f)) // 12
f = 12.6
fmt.Println(int64(f)) // 12
Ergebnis ist 12
in beiden Fällen der Integer-Teil. Um die Rundung "Funktionalität" zu erhalten, fügen Sie einfach 0.5
:
f = 12.3
fmt.Println(int64(f + 0.5)) // 12
f = 12.6
fmt.Println(int64(f + 0.5)) // 13
So weit so gut. Aber wir wollen uns nicht auf ganze Zahlen konzentrieren. Wenn wir würden wollten 1-Fraktion Ziffer abzurunden, würden wir mit 10 multiplizieren, bevor 0.5
Hinzufügen und Konvertieren:
f = 12.31
fmt.Println(float64(int64(f*10+0.5))/10) // 12.3
f = 12.66
fmt.Println(float64(int64(f*10+0.5))/10) // 12.7
Also im Grunde multiplizieren Sie mit dem Kehrwert der Einheit, die Sie runden möchten.Zur Abrundung zu 0.05
Einheiten, multipliziert mit 1/0.05 = 20
:
f = 12.31
fmt.Println(float64(int64(f*20+0.5))/20) // 12.3
f = 12.66
fmt.Println(float64(int64(f*20+0.5))/20) // 12.65
Wrapping diese in eine Funktion:
func Round(x, unit float64) float64 {
return float64(int64(x/unit+0.5)) * unit
}
es verwenden:
fmt.Println(Round(0.363636, 0.05)) // 0.35
fmt.Println(Round(3.232, 0.05)) // 3.25
fmt.Println(Round(0.4888, 0.05)) // 0.5
die Beispiele Versuchen Sie, auf die Go Playground.
Beachten Sie, dass 3.232
mit unit=0.05
Rundung nicht exakt 3.25
drucken, sondern 0.35000000000000003
. Dies liegt daran, dass float64
Zahlen unter Verwendung der endlichen Genauigkeit gespeichert werden, die IEEE-754 Standard genannt wird. Für Details siehe Golang converting float64 to int error.
Beachten Sie auch, dass unit
sein kann "any" Zahl. Wenn es 1
ist, dann rundet Round()
im Grunde die nächste Ganzzahl ab. Wenn es 10
ist, rundet es auf zehn, wenn es 0.01
ist, rundet es auf 2 Bruchstellen ab.
Beachten Sie auch, dass, wenn Sie Round()
mit einer negativen Zahl nennen, könnte man überraschendes Ergebnis:
fmt.Println(Round(-0.363636, 0.05)) // -0.3
fmt.Println(Round(-3.232, 0.05)) // -3.2
fmt.Println(Round(-0.4888, 0.05)) // -0.45
Dies liegt daran, -as sagte earlier- Umwandlung des Integer-Teil hält, und zum Beispiel ganzzahlige Teil von -1.6
ist -1
(das ist größer als -1.6
; während der ganze Teil von 1.6
ist 1
, die weniger als 1.6
ist).
Wenn Sie -0.363636
wollen -0.35
werden statt -0.30
, dann bei negativen Zahlen addieren -0.5
statt 0.5
innerhalb der Round()
Funktion. Sehen Sie unsere verbesserte Round2()
Funktion:
func Round2(x, unit float64) float64 {
if x > 0 {
return float64(int64(x/unit+0.5)) * unit
}
return float64(int64(x/unit-0.5)) * unit
}
und dessen Verwendung:
fmt.Println(Round2(-0.363636, 0.05)) // -0.35
fmt.Println(Round2(-3.232, 0.05)) // -3.25
fmt.Println(Round2(-0.4888, 0.05)) // -0.5
EDIT:
Um Ihren Kommentar Adresse: weil Sie nicht "wie" die nicht -exact 0.35000000000000003
, schlug vor, es zu formatieren und es erneut zu analysieren:
formatted, err := strconv.ParseFloat(fmt.Sprintf("%.2f", rounded), 64)
Und diese „scheinbar“ Ergebnisse in dem genauen Ergebnis, da es Druck geben 0.35
genau.
Aber das ist nur eine "Illusion". Da 0.35
nicht mit endlichen Bits mit IEEE-754-Standard dargestellt werden, egal, was Sie mit der Nummer tun, wenn Sie es in einem Wert vom Typ speichern float64
, wird es nicht genau seine 0.35
(aber eine IEEE-754-Nummer sehr nah dran zu sein). Was Sie sehen, ist fmt.Println()
Drucken es als 0.35
, weil fmt.Println()
bereits einige Rundungen macht.
Aber wenn man es mit einer höheren Genauigkeit zu drucken versuchen:
fmt.Printf("%.30f\n", Round(0.363636, 0.05))
fmt.Printf("%.30f\n", Round(3.232, 0.05))
fmt.Printf("%.30f\n", Round(0.4888, 0.05))
Ausgang: es ist nicht besser (vielleicht sogar hässlicher sein): versuchen Sie es auf dem Go Playground:
0.349999999999999977795539507497
3.250000000000000000000000000000
0.500000000000000000000000000000
Beachten Sie, dass auf die andere Hand 3.25
und 0.5
sind genau, weil sie mit endlichen Bits genau dargestellt werden können, da in binär dargestellt:
3.25 = 3 + 0.25 = 11.01binary
0.5 = 0.1binary
Was ist die Lektion? Es lohnt sich nicht formatieren und neu Parsen das Ergebnis, da es nicht genau sein wird, entweder (nur ein anderer float64
Wert, der fmt.Println()
Formatierung auf Regeln auf Standard -nach könnte in Druck schöner sein). Wenn Sie schön gedruckte Format wollen, formatieren Sie nur mit Präzision, wie:
func main() {
fmt.Printf("%.3f\n", Round(0.363636, 0.05))
fmt.Printf("%.3f\n", Round(3.232, 0.05))
fmt.Printf("%.3f\n", Round(0.4888, 0.05))
}
func Round(x, unit float64) float64 {
return float64(int64(x/unit+0.5)) * unit
}
Und es wird genau (es versucht, auf den Go Playground) sein:
0.350
3.250
0.500
Oder sich nur durch 100
multiplizieren und die Arbeit mit ganze Zahlen, so dass keine Darstellung oder Rundungsfehler auftreten können.
Ich habe eine online gefunden, aber es tut nicht ganz das, was ich in der Frage gefragt:/ – Acidic
Related: [Go: Converting Float64 zu Int mit Multiplikator] (http://StackOverflow.com/Questions/33206059/ go-converting-float64-to-int-with-multiplier) – icza
Wenn Sie eine Rundungsfunktion haben, die korrekte Ergebnisse liefert, müssen Sie nur die Genauigkeit des Ergebnisses verwalten, indem Sie es abschneiden. Eine Art ham-fisted Ansatz für das wäre https://play.golang.org/p/DRTTkQQI42 (nicht getestet Flanke) – abhink