rounding.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Copyright 2009 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Multiprecision decimal numbers.
  5. // For floating-point formatting only; not general purpose.
  6. // Only operations are assign and (binary) left/right shift.
  7. // Can do binary floating point in multiprecision decimal precisely
  8. // because 2 divides 10; cannot do decimal floating point
  9. // in multiprecision binary precisely.
  10. package decimal
  11. type floatInfo struct {
  12. mantbits uint
  13. expbits uint
  14. bias int
  15. }
  16. var float32info = floatInfo{23, 8, -127}
  17. var float64info = floatInfo{52, 11, -1023}
  18. // roundShortest rounds d (= mant * 2^exp) to the shortest number of digits
  19. // that will let the original floating point value be precisely reconstructed.
  20. func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
  21. // If mantissa is zero, the number is zero; stop now.
  22. if mant == 0 {
  23. d.nd = 0
  24. return
  25. }
  26. // Compute upper and lower such that any decimal number
  27. // between upper and lower (possibly inclusive)
  28. // will round to the original floating point number.
  29. // We may see at once that the number is already shortest.
  30. //
  31. // Suppose d is not denormal, so that 2^exp <= d < 10^dp.
  32. // The closest shorter number is at least 10^(dp-nd) away.
  33. // The lower/upper bounds computed below are at distance
  34. // at most 2^(exp-mantbits).
  35. //
  36. // So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits),
  37. // or equivalently log2(10)*(dp-nd) > exp-mantbits.
  38. // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32).
  39. minexp := flt.bias + 1 // minimum possible exponent
  40. if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
  41. // The number is already shortest.
  42. return
  43. }
  44. // d = mant << (exp - mantbits)
  45. // Next highest floating point number is mant+1 << exp-mantbits.
  46. // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1.
  47. upper := new(decimal)
  48. upper.Assign(mant*2 + 1)
  49. upper.Shift(exp - int(flt.mantbits) - 1)
  50. // d = mant << (exp - mantbits)
  51. // Next lowest floating point number is mant-1 << exp-mantbits,
  52. // unless mant-1 drops the significant bit and exp is not the minimum exp,
  53. // in which case the next lowest is mant*2-1 << exp-mantbits-1.
  54. // Either way, call it mantlo << explo-mantbits.
  55. // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1.
  56. var mantlo uint64
  57. var explo int
  58. if mant > 1<<flt.mantbits || exp == minexp {
  59. mantlo = mant - 1
  60. explo = exp
  61. } else {
  62. mantlo = mant*2 - 1
  63. explo = exp - 1
  64. }
  65. lower := new(decimal)
  66. lower.Assign(mantlo*2 + 1)
  67. lower.Shift(explo - int(flt.mantbits) - 1)
  68. // The upper and lower bounds are possible outputs only if
  69. // the original mantissa is even, so that IEEE round-to-even
  70. // would round to the original mantissa and not the neighbors.
  71. inclusive := mant%2 == 0
  72. // Now we can figure out the minimum number of digits required.
  73. // Walk along until d has distinguished itself from upper and lower.
  74. for i := 0; i < d.nd; i++ {
  75. l := byte('0') // lower digit
  76. if i < lower.nd {
  77. l = lower.d[i]
  78. }
  79. m := d.d[i] // middle digit
  80. u := byte('0') // upper digit
  81. if i < upper.nd {
  82. u = upper.d[i]
  83. }
  84. // Okay to round down (truncate) if lower has a different digit
  85. // or if lower is inclusive and is exactly the result of rounding
  86. // down (i.e., and we have reached the final digit of lower).
  87. okdown := l != m || inclusive && i+1 == lower.nd
  88. // Okay to round up if upper has a different digit and either upper
  89. // is inclusive or upper is bigger than the result of rounding up.
  90. okup := m != u && (inclusive || m+1 < u || i+1 < upper.nd)
  91. // If it's okay to do either, then round to the nearest one.
  92. // If it's okay to do only one, do it.
  93. switch {
  94. case okdown && okup:
  95. d.Round(i + 1)
  96. return
  97. case okdown:
  98. d.RoundDown(i + 1)
  99. return
  100. case okup:
  101. d.RoundUp(i + 1)
  102. return
  103. }
  104. }
  105. }