@@ -80,39 +80,80 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
80
80
// would round to the original mantissa and not the neighbors.
81
81
inclusive := mant % 2 == 0
82
82
83
+ // As we walk the digits we want to know whether rounding up would fall
84
+ // within the upper bound. This is tracked by upperdelta:
85
+ //
86
+ // If upperdelta == 0, the digits of d and upper are the same so far.
87
+ //
88
+ // If upperdelta == 1, we saw a difference of 1 between d and upper on a
89
+ // previous digit and subsequently only 9s for d and 0s for upper.
90
+ // (Thus rounding up may fall outside the bound, if it is exclusive.)
91
+ //
92
+ // If upperdelta == 2, then the difference is greater than 1
93
+ // and we know that rounding up falls within the bound.
94
+ var upperdelta uint8
95
+
83
96
// Now we can figure out the minimum number of digits required.
84
97
// Walk along until d has distinguished itself from upper and lower.
85
- for i := 0 ; i < d .nd ; i ++ {
98
+ for ui := 0 ; ; ui ++ {
99
+ // lower, d, and upper may have the decimal points at different
100
+ // places. In this case upper is the longest, so we iterate from
101
+ // ui==0 and start li and mi at (possibly) -1.
102
+ mi := ui - upper .dp + d .dp
103
+ if mi >= d .nd {
104
+ break
105
+ }
106
+ li := ui - upper .dp + lower .dp
86
107
l := byte ('0' ) // lower digit
87
- if i < lower .nd {
88
- l = lower .d [i ]
108
+ if li >= 0 && li < lower .nd {
109
+ l = lower .d [li ]
110
+ }
111
+ m := byte ('0' ) // middle digit
112
+ if mi >= 0 {
113
+ m = d .d [mi ]
89
114
}
90
- m := d .d [i ] // middle digit
91
115
u := byte ('0' ) // upper digit
92
- if i < upper .nd {
93
- u = upper .d [i ]
116
+ if ui < upper .nd {
117
+ u = upper .d [ui ]
94
118
}
95
119
96
120
// Okay to round down (truncate) if lower has a different digit
97
121
// or if lower is inclusive and is exactly the result of rounding
98
122
// down (i.e., and we have reached the final digit of lower).
99
- okdown := l != m || inclusive && i + 1 == lower .nd
123
+ okdown := l != m || inclusive && li + 1 == lower .nd
100
124
125
+ switch {
126
+ case upperdelta == 0 && m + 1 < u :
127
+ // Example:
128
+ // m = 12345xxx
129
+ // u = 12347xxx
130
+ upperdelta = 2
131
+ case upperdelta == 0 && m != u :
132
+ // Example:
133
+ // m = 12345xxx
134
+ // u = 12346xxx
135
+ upperdelta = 1
136
+ case upperdelta == 1 && (m != '9' || u != '0' ):
137
+ // Example:
138
+ // m = 1234598x
139
+ // u = 1234600x
140
+ upperdelta = 2
141
+ }
101
142
// Okay to round up if upper has a different digit and either upper
102
143
// is inclusive or upper is bigger than the result of rounding up.
103
- okup := m != u && (inclusive || m + 1 < u || i + 1 < upper .nd )
144
+ okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui + 1 < upper .nd )
104
145
105
146
// If it's okay to do either, then round to the nearest one.
106
147
// If it's okay to do only one, do it.
107
148
switch {
108
149
case okdown && okup :
109
- d .Round (i + 1 )
150
+ d .Round (mi + 1 )
110
151
return
111
152
case okdown :
112
- d .RoundDown (i + 1 )
153
+ d .RoundDown (mi + 1 )
113
154
return
114
155
case okup :
115
- d .RoundUp (i + 1 )
156
+ d .RoundUp (mi + 1 )
116
157
return
117
158
}
118
159
}
0 commit comments