Adding half a unit before cutting to 15 digits matched that one row but turned ROUND(1.5, 14) into 1.50000000000001. ROUND rounds the shortest decimal half away from zero again, with regression tests.
- commit
- 7d292fece5cc049d9f9a371d907ceb9ed8f4c0f8
- parent
- c20d59f81caa4211c2ee0f32f40d24c7577c2595
- author
- Dami <dami.etoile@gmail.com>
- kind
- fix risk score 2.0 of 3, Jev's estimate
@@ -33,7 +33,7 @@ Aliases: `AVG` for `AVERAGE`.
3333 | `NOT(logical)` | The opposite of a logical value |3434 | `OR(logical1, [logical2, ...])` | TRUE if any argument is true |3535 | `PI()` | The number pi |36-| `ROUND(value, [places])` | Round to a number of decimal places, halves away from zero |36+| `ROUND(value, [places])` | Round to a number of decimal places, halves away from zero, on the digits a cell shows: ROUND(1.5, 14) is 1.5 |3737 | `SQRT(value)` | Square root |3838 | `SUM(value1, [value2, ...])` | Sum of numbers |3939 | `TRUE()` | The logical value TRUE |@@ -126,7 +126,7 @@
126126 =ROUND(0.285, 2) 0.29 0.29127127 =ROUND(-2.5) -3 -3128128 =ROUND(1.5, 0.9) 2 2129-=ROUND(1.23456789012345, 14) 1.23456789012346 1.23456789012346129+=ROUND(1.23456789012345, 14) 1.23456789012345 1.23456789012346 on purpose: 012 rounds the shortest decimal half away from zero, so an exact input stays exact; Sheets' ...346 fits only a rule that also turns ROUND(1.5, 14) into 1.50000000000001130130 =ROUNDUP(0.1+0.2, 1) 0.3 0.3131131 =ROUNDDOWN(1-0.9, 1) 0.1 0.1132132 =TRUNC(1234, -2) 1200 1200@@ -140,7 +140,7 @@ func init() {
140140 &FuncDef{Name: "ABS", Args: "value", Desc: "Absolute value", Min: 1, Max: 1, eval: math1(math.Abs), format: inherit},141141 &FuncDef{Name: "INT", Args: "value", Desc: "Round down to the nearest integer", Min: 1, Max: 1, eval: math1(math.Floor), format: inherit},142142 &FuncDef{Name: "SQRT", Args: "value", Desc: "Square root", Min: 1, Max: 1, eval: math1(math.Sqrt)},143- &FuncDef{Name: "ROUND", Args: "value, [places]", Desc: "Round to a number of decimal places, halves away from zero", Min: 1, Max: 2,143+ &FuncDef{Name: "ROUND", Args: "value, [places]", Desc: "Round to a number of decimal places, halves away from zero, on the digits a cell shows: ROUND(1.5, 14) is 1.5", Min: 1, Max: 2,144144 eval: rounder(numfmt.HalfUp), format: inheritFrom(0)},145145 &FuncDef{Name: "MOD", Args: "dividend, divisor", Desc: "Remainder, with the sign of the divisor: MOD(0.3, 0.1) is 0.1 as in Excel, where Sheets gives -5.55E-17", Min: 2, Max: 2,146146 eval: numeric(func(x []float64) Value {@@ -152,7 +152,10 @@ func TestRound(t *testing.T) {
152152 {2.675, 2, HalfUp, 2.68},153153 {-2.5, 0, HalfUp, -3},154154 {1234.5, -2, HalfUp, 1200},155- {1.23456789012345, 14, HalfUp, 1.23456789012346}, // the half added carries, as in Sheets155+ {-1.005, 2, HalfUp, -1.01},156+ {1.5, 14, HalfUp, 1.5}, // exact inputs stay exact157+ {0.1 + 0.2, 15, HalfUp, 0.3},158+ {1.23456789012345, 14, HalfUp, 1.23456789012345}, // Sheets says ...346156159 {1.23456789012345, 15, HalfUp, 1.23456789012345},157160 {2.301, 1, Up, 2.4},158161 {-2.39, 1, Down, -2.3},@@ -87,18 +87,8 @@ func increment(d []byte, point int) ([]byte, int) {
8787 8888 // Round rounds x to places decimal places (negative places round to8989 // tens, hundreds...) with mode, on x's 15 significant digits.90-//91-// HalfUp rounds as Sheets' ROUND does: it adds half a unit of the last92-// place kept and drops the digits after it, on the sum's 15 significant93-// digits. That is Fixed's rounding, except at the 15th digit itself,94-// where the half added carries: ROUND(1.23456789012345, 14) is95-// 1.23456789012346.9690 func Round(x float64, places int, mode Rounding) float64 {97- a := math.Abs(x)98- if mode == HalfUp {99- a, mode = a+0.5*math.Pow10(-places), Down100- }101- whole, frac := Fixed(a, places, mode)91+ whole, frac := Fixed(x, places, mode)10292 s := whole10393 if s == "" {10494 s = "0"@@ -30,8 +30,12 @@ func TestSheetsSemantics(t *testing.T) {
3030 {`=COUNTIF(E1:E3, 0.1+0.2+1.2)`, num(1)},3131 {"=123456789012345678", num(123456789012345000)},3232 {"=123456789012345678=123456789012345000", boolean(true)},33- {"=ROUND(1.23456789012345, 14)=1.23456789012346", boolean(true)}, // the half added carries34- {"=ROUND(2.675, 2)", num(2.68)},33+ // ROUND is half away from zero on the shortest decimal, as in34+ // Sheets and Excel; exact inputs stay exact.35+ {"=ROUND(2.675, 2)=2.68", boolean(true)},36+ {"=ROUND(-1.005, 2)=-1.01", boolean(true)},37+ {"=ROUND(1.5, 14)-1.5=0", boolean(true)},38+ {"=ROUND(0.1+0.2, 15)-0.3=0", boolean(true)},3539 {"=ROUND(-2.5)", num(-3)},3640 // Errors and conditions.3741 {"=IFERROR(NA())", Value{}},