diff options
-rwxr-xr-x | lib/pure/math.nim | 13 | ||||
-rwxr-xr-x | lib/pure/strutils.nim | 60 | ||||
-rwxr-xr-x | lib/system/ansi_c.nim | 5 | ||||
-rwxr-xr-x | rod/ast.nim | 2 | ||||
-rwxr-xr-x | rod/astalgo.nim | 44 | ||||
-rwxr-xr-x | rod/ccgexprs.nim | 16 | ||||
-rwxr-xr-x | rod/cgen.nim | 3 | ||||
-rwxr-xr-x | rod/ecmasgen.nim | 8 | ||||
-rw-r--r-- | rod/rodutils.nim | 27 | ||||
-rwxr-xr-x | rod/ropes.nim | 14 | ||||
-rwxr-xr-x | tests/accept/run/spec.csv | 1 | ||||
-rw-r--r-- | tests/accept/run/tfloat3.nim | 18 | ||||
-rwxr-xr-x | todo.txt | 1 |
13 files changed, 156 insertions, 56 deletions
diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 89a0ccd25..dc6133901 100755 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2010 Andreas Rumpf +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -24,6 +24,17 @@ const PI* = 3.1415926535897932384626433 ## the circle constant PI (Ludolph's number) E* = 2.71828182845904523536028747 ## Euler's number + MaxFloat64Precision* = 16 ## maximum number of meaningful digits + ## after the decimal point for Nimrod's + ## ``float64`` type. + MaxFloat32Precision* = 8 ## maximum number of meaningful digits + ## after the decimal point for Nimrod's + ## ``float32`` type. + MaxFloatPrecision* = MaxFloat64Precision ## maximum number of + ## meaningful digits + ## after the decimal point + ## for Nimrod's ``float`` type. + type TFloatClass* = enum ## describes the class a floating point value belongs to. ## This is the type that is returned by `classify`. diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index f6de035a8..c794b5a74 100755 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -935,6 +935,60 @@ proc editDistance*(a, b: string): int {.noSideEffect, row[p] = x result = row[e] #dealloc(row) + + +# floating point formating: + +proc c_sprintf(buf, frmt: CString) {.nodecl, importc: "sprintf", varargs, + noSideEffect.} + +type + TFloatFormat* = enum + ffDefault, ## use the shorter floating point notation + ffDecimal, ## use decimal floating point notation + ffScientific ## use scientific notation (using ``e``) character + +proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault, + precision = 16): string {.noSideEffect, + rtl, extern: "nsu$1".} = + ## converts a floating point value `f` to a string. + ## + ## If ``format == ffDecimal`` then precision is the number of digits to + ## be printed after the decimal point. + ## If ``format == ffScientific`` then precision is the maximum number + ## of significant digits to be printed. + ## `precision`'s default value is the maximum number of meaningful digits + ## after the decimal point for Nimrod's ``biggestFloat`` type. + const floatFormatToChar: array[TFloatFormat, char] = ['g', 'f', 'e'] + var + frmtstr: array[0..5, char] + buf: array[0..80, char] + frmtstr[0] = '%' + frmtstr[1] = '#' + if precision > 0: + frmtstr[2] = '.' + frmtstr[3] = '*' + frmtstr[4] = floatFormatToChar[format] + frmtstr[5] = '\0' + c_sprintf(buf, frmtstr, precision, f) + else: + frmtstr[2] = floatFormatToChar[format] + frmtstr[3] = '\0' + c_sprintf(buf, frmtstr, f) + result = $buf + +proc formatFloat*(f: float, format: TFloatFormat = ffDefault, + precision = 16): string {.noSideEffect, + rtl, extern: "nsu$1".} = + ## converts a floating point value `f` to a string. + ## + ## If ``format == ffDecimal`` then precision is the number of digits to + ## be printed after the decimal point. + ## If ``format == ffScientific`` then precision is the maximum number + ## of significant digits to be printed. + ## `precision`'s default value is the maximum number of meaningful digits + ## after the decimal point for Nimrod's ``float`` type. + result = formatBiggestFloat(f, format, precision) {.pop.} @@ -944,5 +998,7 @@ when isMainModule: assert align("1232", 6) == " 1232" echo wordWrap(""" this is a long text -- muchlongerthan10chars and here it goes""", 10, false) - - + assert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001" + assert formatBiggestFloat(0.00000000001, ffScientific, 1) == "1.0e-11" + + diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index e9300949b..362b73297 100755 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -1,7 +1,7 @@ # # # Nimrod's Runtime Library -# (c) Copyright 2009 Andreas Rumpf +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -34,7 +34,8 @@ var c_stdout {.importc: "stdout", noDecl.}: C_TextFileStar c_stderr {.importc: "stderr", noDecl.}: C_TextFileStar -var # constants faked as variables: +# constants faked as variables: +var SIGINT {.importc: "SIGINT", nodecl.}: cint SIGSEGV {.importc: "SIGSEGV", nodecl.}: cint SIGABRT {.importc: "SIGABRT", nodecl.}: cint diff --git a/rod/ast.nim b/rod/ast.nim index 4b16078fc..47d3d8621 100755 --- a/rod/ast.nim +++ b/rod/ast.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2009 Andreas Rumpf +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/rod/astalgo.nim b/rod/astalgo.nim index 894af5b05..27e3ccfea 100755 --- a/rod/astalgo.nim +++ b/rod/astalgo.nim @@ -12,7 +12,7 @@ # the data structures here are used in various places of the compiler. import - ast, nhashes, strutils, options, msgs, ropes, idents + ast, nhashes, strutils, options, msgs, ropes, idents, rodutils proc hashNode*(p: PObject): THash proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope @@ -327,7 +327,8 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, of nkCharLit..nkInt64Lit: appf(result, ",$n$1\"intVal\": $2", [istr, toRope(n.intVal)]) of nkFloatLit, nkFloat32Lit, nkFloat64Lit: - appf(result, ",$n$1\"floatVal\": $2", [istr, toRopeF(n.floatVal)]) + appf(result, ",$n$1\"floatVal\": $2", + [istr, toRope(n.floatVal.ToStrMaxPrecision)]) of nkStrLit..nkTripleStrLit: appf(result, ",$n$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) of nkSym: @@ -396,7 +397,8 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope = of nkCharLit..nkInt64Lit: appf(result, ",$n$1\"intVal\": $2", [istr, toRope(n.intVal)]) of nkFloatLit, nkFloat32Lit, nkFloat64Lit: - appf(result, ",$n$1\"floatVal\": $2", [istr, toRopeF(n.floatVal)]) + appf(result, ",$n$1\"floatVal\": $2", + [istr, toRope(n.floatVal.ToStrMaxPrecision)]) of nkStrLit..nkTripleStrLit: appf(result, ",$n$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) of nkSym: @@ -430,12 +432,13 @@ proc debug(n: PNode) = writeln(stdout, ropeToStr(debugTree(n, 0, 100))) const - EmptySeq = @ [] + EmptySeq = @[] proc nextTry(h, maxHash: THash): THash = - result = ((5 * h) + 1) and maxHash # For any initial h in range(maxHash), repeating that maxHash times - # generates each int in range(maxHash) exactly once (see any text on - # random-number generation for proof). + result = ((5 * h) + 1) and maxHash + # For any initial h in range(maxHash), repeating that maxHash times + # generates each int in range(maxHash) exactly once (see any text on + # random-number generation for proof). proc objectSetContains(t: TObjectSet, obj: PObject): bool = # returns true whether n is in t @@ -498,7 +501,8 @@ proc TableRawGet(t: TTable, key: PObject): int = h = nextTry(h, high(t.data)) result = - 1 -proc TableSearch(t: TTable, key, closure: PObject, comparator: TCmpProc): PObject = +proc TableSearch(t: TTable, key, closure: PObject, + comparator: TCmpProc): PObject = var h: THash h = hashNode(key) and high(t.data) # start with real hash value while t.data[h].key != nil: @@ -510,8 +514,7 @@ proc TableSearch(t: TTable, key, closure: PObject, comparator: TCmpProc): PObjec result = nil proc TableGet(t: TTable, key: PObject): PObject = - var index: int - index = TableRawGet(t, key) + var index = TableRawGet(t, key) if index >= 0: result = t.data[index].val else: result = nil @@ -533,8 +536,7 @@ proc TableEnlarge(t: var TTable) = swap(t.data, n) proc TablePut(t: var TTable, key, val: PObject) = - var index: int - index = TableRawGet(t, key) + var index = TableRawGet(t, key) if index >= 0: t.data[index].val = val else: @@ -692,20 +694,17 @@ proc IdTableRawGet(t: TIdTable, key: int): int = result = - 1 proc IdTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool = - var index: int - index = IdTableRawGet(t, key.id) + var index = IdTableRawGet(t, key.id) if index >= 0: result = t.data[index].key == key else: result = false proc IdTableGet(t: TIdTable, key: PIdObj): PObject = - var index: int - index = IdTableRawGet(t, key.id) + var index = IdTableRawGet(t, key.id) if index >= 0: result = t.data[index].val else: result = nil proc IdTableGet(t: TIdTable, key: int): PObject = - var index: int - index = IdTableRawGet(t, key) + var index = IdTableRawGet(t, key) if index >= 0: result = t.data[index].val else: result = nil @@ -797,8 +796,7 @@ proc IITableRawGet(t: TIITable, key: int): int = result = - 1 proc IITableGet(t: TIITable, key: int): int = - var index: int - index = IITableRawGet(t, key) + var index = IITableRawGet(t, key) if index >= 0: result = t.data[index].val else: result = InvalidKey @@ -813,15 +811,13 @@ proc IITableRawInsert(data: var TIIPairSeq, key, val: int) = data[h].val = val proc IITablePut(t: var TIITable, key, val: int) = - var - index: int - n: TIIPairSeq - index = IITableRawGet(t, key) + var index = IITableRawGet(t, key) if index >= 0: assert(t.data[index].key != InvalidKey) t.data[index].val = val else: if mustRehash(len(t.data), t.counter): + var n: TIIPairSeq newSeq(n, len(t.data) * growthFactor) for i in countup(0, high(n)): n[i].key = InvalidKey for i in countup(0, high(t.data)): diff --git a/rod/ccgexprs.nim b/rod/ccgexprs.nim index aaf3a51ed..294b3e510 100755 --- a/rod/ccgexprs.nim +++ b/rod/ccgexprs.nim @@ -1,7 +1,7 @@ # # # The Nimrod Compiler -# (c) Copyright 2010 Andreas Rumpf +# (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -12,7 +12,8 @@ proc intLiteral(i: biggestInt): PRope = if (i > low(int32)) and (i <= high(int32)): result = toRope(i) - elif i == low(int32): # Nimrod has the same bug for the same reasons :-) + elif i == low(int32): + # Nimrod has the same bug for the same reasons :-) result = toRope("(-2147483647 -1)") elif i > low(int64): result = ropef("IL64($1)", [toRope(i)]) @@ -76,16 +77,7 @@ proc genLiteral(p: BProc, v: PNode, ty: PType): PRope = else: result = makeCString(v.strVal) of nkFloatLit..nkFloat64Lit: - var f = v.floatVal - if f != f: - result = toRope("NAN") - elif f == 0.0: - result = toRopeF(f) - elif f == 0.5 * f: - if f > 0.0: result = toRope("INF") - else: result = toRope("-INF") - else: - result = toRopeF(f) + result = toRope(v.floatVal.ToStrMaxPrecision) else: InternalError(v.info, "genLiteral(" & $v.kind & ')') result = nil diff --git a/rod/cgen.nim b/rod/cgen.nim index d57d5250a..360b46a3b 100755 --- a/rod/cgen.nim +++ b/rod/cgen.nim @@ -13,7 +13,8 @@ import ast, astalgo, strutils, nhashes, trees, platform, magicsys, extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, - times, ropes, math, passes, rodread, wordrecg, rnimsyn, treetab, cgmeth + times, ropes, math, passes, rodread, wordrecg, rnimsyn, treetab, cgmeth, + rodutils when options.hasTinyCBackend: import tccgen diff --git a/rod/ecmasgen.nim b/rod/ecmasgen.nim index 62cb5b781..ca3ab8ddb 100755 --- a/rod/ecmasgen.nim +++ b/rod/ecmasgen.nim @@ -14,7 +14,7 @@ import ast, astalgo, strutils, nhashes, trees, platform, magicsys, extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os, - times, ropes, math, passes, ccgutils, wordrecg, rnimsyn, rodread + times, ropes, math, passes, ccgutils, wordrecg, rnimsyn, rodread, rodutils proc ecmasgenPass*(): TPass # implementation @@ -115,7 +115,7 @@ proc mapType(typ: PType): TEcmasTypeKind = proc mangle(name: string): string = result = "" - for i in countup(0, len(name) + 0 - 1): + for i in countup(0, len(name) - 1): case name[i] of 'A'..'Z': add(result, chr(ord(name[i]) - ord('A') + ord('a'))) @@ -1357,11 +1357,11 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) = of nkFloatLit..nkFloat64Lit: f = n.floatVal if f != f: r.res = toRope("NaN") - elif f == 0.0: r.res = toRopeF(f) + elif f == 0.0: r.res = toRope("0.0") elif f == 0.5 * f: if f > 0.0: r.res = toRope("Infinity") else: r.res = toRope("-Infinity") - else: r.res = toRopeF(f) + else: r.res = toRope(f.ToStrMaxPrecision) of nkBlockExpr: genBlock(p, n, r) of nkIfExpr: genIfExpr(p, n, r) of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit: diff --git a/rod/rodutils.nim b/rod/rodutils.nim new file mode 100644 index 000000000..dad5d679f --- /dev/null +++ b/rod/rodutils.nim @@ -0,0 +1,27 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2011 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Utilities for the compiler. Aim is to reduce the coupling between +## the compiler and the evolving stdlib. + +proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", nodecl, varargs.} + +proc ToStrMaxPrecision*(f: BiggestFloat): string = + if f != f: + result = "NAN" + elif f == 0.0: + result = "0.0" + elif f == 0.5 * f: + if f > 0.0: result = "INF" + else: result = "-INF" + else: + var buf: array [0..80, char] + c_sprintf(buf, "%#.16e", f) + result = $buf + diff --git a/rod/ropes.nim b/rod/ropes.nim index 542c6b3b3..eb7022110 100755 --- a/rod/ropes.nim +++ b/rod/ropes.nim @@ -87,7 +87,6 @@ proc app*(a: var PRope, b: PRope) proc app*(a: var PRope, b: string) proc prepend*(a: var PRope, b: PRope) proc toRope*(s: string): PRope -proc toRopeF*(r: BiggestFloat): PRope proc toRope*(i: BiggestInt): PRope proc ropeLen*(a: PRope): int proc WriteRope*(head: PRope, filename: string) @@ -270,7 +269,7 @@ proc con(a: openarray[PRope]): PRope = for i in countup(0, high(a)): result = con(result, a[i]) proc toRope(i: BiggestInt): PRope = result = toRope($i) -proc toRopeF(r: BiggestFloat): PRope = result = toRope($r) +#proc toRopeF*(r: BiggestFloat): PRope = result = toRope($r) proc app(a: var PRope, b: PRope) = a = con(a, b) proc app(a: var PRope, b: string) = a = con(a, b) proc prepend(a: var PRope, b: PRope) = a = con(b, a) @@ -303,11 +302,10 @@ proc WriteRope(head: PRope, filename: string) = rawMessage(errCannotOpenFile, filename) proc ropef(frmt: TFormatStr, args: openarray[PRope]): PRope = - var i, j, length, start, num: int - i = 0 - length = len(frmt) + var i = 0 + var length = len(frmt) result = nil - num = 0 + var num = 0 while i <= length - 1: if frmt[i] == '$': inc(i) # skip '$' @@ -320,7 +318,7 @@ proc ropef(frmt: TFormatStr, args: openarray[PRope]): PRope = app(result, args[num]) inc(num) of '0'..'9': - j = 0 + var j = 0 while true: j = (j * 10) + Ord(frmt[i]) - ord('0') inc(i) @@ -333,7 +331,7 @@ proc ropef(frmt: TFormatStr, args: openarray[PRope]): PRope = app(result, tnl) inc(i) else: InternalError("ropes: invalid format string $" & frmt[i]) - start = i + var start = i while (i <= length - 1): if (frmt[i] != '$'): inc(i) else: break diff --git a/tests/accept/run/spec.csv b/tests/accept/run/spec.csv index 4bb94ed74..075e4e67e 100755 --- a/tests/accept/run/spec.csv +++ b/tests/accept/run/spec.csv @@ -27,6 +27,7 @@ tfinally2.nim;ABCD tfinally3.nim;false tfloat1.nim;Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow] tfloat2.nim;Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp] +tfloat3.nim;Nimrod 3.4368930843, 0.3299290698 C double: 3.4368930843, 0.3299290698 tformat.nim;Hi Andreas! How do you feel, Rumpf? thintoff.nim;0 tinit.nim;Hello from module! Hello from main module! diff --git a/tests/accept/run/tfloat3.nim b/tests/accept/run/tfloat3.nim new file mode 100644 index 000000000..72acce958 --- /dev/null +++ b/tests/accept/run/tfloat3.nim @@ -0,0 +1,18 @@ + +import math, strutils + +{.emit: """ +void printFloats(void) { + double y = 1.234567890123456789; + + printf("C double: %.10f, %.10f ", exp(y), cos(y)); +} +""".} + +proc c_printf(frmt: CString) {.importc: "printf", header: "<stdio.h>", varargs.} +proc printFloats {.importc, nodecl.} + +var x: float = 1.234567890123456789 +c_printf("Nimrod %.10f, %.10f ", exp(x), cos(x)) +printFloats() + diff --git a/todo.txt b/todo.txt index d958fb321..0c77c484e 100755 --- a/todo.txt +++ b/todo.txt @@ -59,7 +59,6 @@ Low priority Library ------- -- float formatting - locale support - conversion between character sets - bignums |