writeText for float rewritten to re-use Nim's call to sprintf
This commit is contained in:
parent
9bbbf376d0
commit
2c32157fd3
1 changed files with 17 additions and 144 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
import
|
import
|
||||||
stew/ptrops,
|
stew/ptrops,
|
||||||
inputs, outputs, buffers, async_backend, multisync,
|
inputs, outputs, buffers, async_backend, multisync,
|
||||||
math
|
system/formatfloat
|
||||||
|
|
||||||
template matchingIntType(T: type int64): type = uint64
|
template matchingIntType(T: type int64): type = uint64
|
||||||
template matchingIntType(T: type int32): type = uint32
|
template matchingIntType(T: type int32): type = uint32
|
||||||
|
|
@ -92,149 +92,22 @@ proc writeText*(s: OutputStream, x: CompiledIntTypes) =
|
||||||
else:
|
else:
|
||||||
writeText(s, MatchingUInt(x))
|
writeText(s, MatchingUInt(x))
|
||||||
|
|
||||||
when defined(aa):
|
when defined(c):
|
||||||
proc writeText*(s: OutputStream, x: float64|float) = # this version mostly works, but does not account for rounding error
|
|
||||||
var whole = x.int
|
|
||||||
writeText(s, whole)
|
|
||||||
var frac = abs(x - whole.float)
|
|
||||||
if frac == 0.0:
|
|
||||||
return
|
|
||||||
write s, '.'
|
|
||||||
var limit: byte = 8
|
|
||||||
while (frac != 0.0) and (limit > 0):
|
|
||||||
limit -= 1
|
|
||||||
frac *= 10.0
|
|
||||||
whole = frac.int
|
|
||||||
frac -= whole.float
|
|
||||||
write s, char(ord('0') + whole)
|
|
||||||
|
|
||||||
when defined(bb):
|
proc writeText*(s: OutputStream, x: float64|float32|float) =
|
||||||
proc writeText*(s: OutputStream, x: float64|float) = # this version just prints the integer part
|
## Write the floating point number to the output stream. It has less overhead
|
||||||
writeText(s, x.int)
|
## than `$` because it is directly written to the stream without
|
||||||
|
## allocating a standard Nim 'string'.
|
||||||
when defined(cc):
|
##
|
||||||
proc writeText*(s: OutputStream, x: float64|float) = # this version uses ftoa of stdlibc
|
## Because this procedure uses stdlib, it is only active when nim compiles
|
||||||
proc floatToStr(x: float): string {.magic: "FloatToStr", noSideEffect.}
|
## with the 'c' flag. Otherwise, float types fall back to the generic writeText
|
||||||
writeText(s, floatToStr(x))
|
## procedure.
|
||||||
|
var buffer: array[65, char]
|
||||||
when defined(dd):
|
discard writeFloatToBuffer(buffer, x)
|
||||||
proc writeText*(s: OutputStream, x: float64|float) = # this version uses ftoa of stdlibc
|
for index in 0 ..< 65:
|
||||||
write s, $x
|
if buffer[index] == '\0':
|
||||||
|
|
||||||
when defined(ee):
|
|
||||||
proc writeText*(s: OutputStream, x: float64|float) = # this version mostly works, but does not account for rounding error
|
|
||||||
if x == 0.0:
|
|
||||||
write s, "0.0"
|
|
||||||
return
|
|
||||||
if x < 0.0:
|
|
||||||
write s, '-'
|
|
||||||
var frac = x.abs
|
|
||||||
var place = log10(frac).int
|
|
||||||
if place < 0:
|
|
||||||
place = 0
|
|
||||||
frac /= pow(10.0, place.float)
|
|
||||||
var whole: int
|
|
||||||
while (frac != 0.0) and (place > -100):
|
|
||||||
if place == -1:
|
|
||||||
write s, '.'
|
|
||||||
whole = frac.int
|
|
||||||
write s, char(ord('0') + whole)
|
|
||||||
frac = (frac - whole.float) * 10.0
|
|
||||||
place -= 1
|
|
||||||
|
|
||||||
when defined(ff):
|
|
||||||
proc writeText*(s: OutputStream, x: float64|float) = # handles rounding
|
|
||||||
const PRECISION_LIMIT = 16
|
|
||||||
const DECIMAL_POINT: uint8 = 255
|
|
||||||
if x == 0.0:
|
|
||||||
write s, "0.0"
|
|
||||||
return
|
|
||||||
var digits: array[322, byte]
|
|
||||||
var index: int = 0
|
|
||||||
if x < 0.0:
|
|
||||||
write s, '-'
|
|
||||||
var precision: int = 0
|
|
||||||
var firstDigitFound = false
|
|
||||||
var decimalPointIndex = -1
|
|
||||||
var frac = x.abs
|
|
||||||
var place = log10(frac).int
|
|
||||||
if place < 0:
|
|
||||||
place = 0
|
|
||||||
frac /= pow(10.0, place.float)
|
|
||||||
var whole: uint8
|
|
||||||
#
|
|
||||||
# run through the digits:
|
|
||||||
#
|
|
||||||
while (frac != 0.0) and (place > -317) and (precision < PRECISION_LIMIT):
|
|
||||||
if place == -1:
|
|
||||||
digits[index] = DECIMAL_POINT
|
|
||||||
decimalPointIndex = index
|
|
||||||
index += 1
|
|
||||||
whole = frac.uint8
|
|
||||||
digits[index] = whole
|
|
||||||
index += 1
|
|
||||||
if firstDigitFound:
|
|
||||||
precision += 1
|
|
||||||
else:
|
|
||||||
if whole != 0.uint8:
|
|
||||||
firstDigitFound = true
|
|
||||||
precision += 1
|
|
||||||
frac = (frac - whole.float) * 10.0
|
|
||||||
place -= 1
|
|
||||||
#
|
|
||||||
# place any missing decimal points as a key marker
|
|
||||||
#
|
|
||||||
if decimalPointIndex == -1:
|
|
||||||
# if decimal point not expressed yet, then add it
|
|
||||||
index += place + 1
|
|
||||||
digits[index] = DECIMAL_POINT
|
|
||||||
decimalPointIndex = index
|
|
||||||
index += 1
|
|
||||||
index -= 1
|
|
||||||
#
|
|
||||||
# remove trailing digits and adjust precision back if need be:
|
|
||||||
#
|
|
||||||
while (digits[index] == 0) and (index > 0):
|
|
||||||
precision -= 1
|
|
||||||
index -= 1
|
|
||||||
#
|
|
||||||
# if still at precision limit, then do rounding:
|
|
||||||
#
|
|
||||||
if precision >= PRECISION_LIMIT:
|
|
||||||
while index > 0:
|
|
||||||
if digits[index] == DECIMAL_POINT:
|
|
||||||
index -= 1
|
|
||||||
continue
|
|
||||||
elif digits[index] >= 5:
|
|
||||||
digits[index - 1] += 1
|
|
||||||
digits[index] = 0
|
|
||||||
if digits[index - 1] < 10:
|
|
||||||
break
|
break
|
||||||
else:
|
write s, buffer[index]
|
||||||
digits[index] = 0
|
|
||||||
break
|
|
||||||
index -= 1
|
|
||||||
#
|
|
||||||
# remove trailing digits and adjust precision back if need be:
|
|
||||||
#
|
|
||||||
while (digits[index] == 0) and (index > 0):
|
|
||||||
precision -= 1
|
|
||||||
index -= 1
|
|
||||||
#
|
|
||||||
# express to the stream
|
|
||||||
#
|
|
||||||
if index < decimalPointIndex:
|
|
||||||
index = decimalPointIndex
|
|
||||||
for i in 0 .. index:
|
|
||||||
let d = digits[i]
|
|
||||||
if d == DECIMAL_POINT:
|
|
||||||
write s, '.'
|
|
||||||
elif d == 10:
|
|
||||||
write s, "10"
|
|
||||||
else:
|
|
||||||
write s, char(ord('0') + d)
|
|
||||||
if digits[index] == DECIMAL_POINT:
|
|
||||||
write s, '0'
|
|
||||||
|
|
||||||
template writeText*(s: OutputStream, str: string) =
|
template writeText*(s: OutputStream, str: string) =
|
||||||
write s, str
|
write s, str
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue