Skip to content

Instantly share code, notes, and snippets.

@Gitart
Forked from gorhill/render_number.go
Created March 11, 2023 13:08
Show Gist options
  • Select an option

  • Save Gitart/f643e697618ef750b4e572af025f1c4f to your computer and use it in GitHub Desktop.

Select an option

Save Gitart/f643e697618ef750b4e572af025f1c4f to your computer and use it in GitHub Desktop.

Revisions

  1. @gorhill gorhill revised this gist Sep 15, 2013. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions ~LICENSE
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
    Version 2, December 2004

    Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>

    Everyone is permitted to copy and distribute verbatim or modified
    copies of this license document, and changing it is allowed as long
    as the name is changed.

    DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

    0. You just DO WHAT THE FUCK YOU WANT TO.
  2. @gorhill gorhill revised this gist Sep 15, 2013. 1 changed file with 0 additions and 13 deletions.
    13 changes: 0 additions & 13 deletions LICENSE
    Original file line number Diff line number Diff line change
    @@ -1,13 +0,0 @@
    DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
    Version 2, December 2004

    Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>

    Everyone is permitted to copy and distribute verbatim or modified
    copies of this license document, and changing it is allowed as long
    as the name is changed.

    DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

    0. You just DO WHAT THE FUCK YOU WANT TO.
  3. @gorhill gorhill revised this gist Sep 15, 2013. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions LICENSE
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
    Version 2, December 2004

    Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>

    Everyone is permitted to copy and distribute verbatim or modified
    copies of this license document, and changing it is allowed as long
    as the name is changed.

    DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

    0. You just DO WHAT THE FUCK YOU WANT TO.
  4. @gorhill gorhill revised this gist Apr 7, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion render_number.go
    Original file line number Diff line number Diff line change
    @@ -14,7 +14,7 @@ Usage: s := RenderFloat(format, n)
    The format parameter tells how to render the number n.
    http://play.golang.org/p/9bWhx3G24a
    http://play.golang.org/p/LXc1Ddm1lJ
    Examples of format strings, given n = 12345.6789:
  5. @gorhill gorhill revised this gist Apr 7, 2013. 1 changed file with 39 additions and 35 deletions.
    74 changes: 39 additions & 35 deletions render_number.go
    Original file line number Diff line number Diff line change
    @@ -14,6 +14,8 @@ Usage: s := RenderFloat(format, n)
    The format parameter tells how to render the number n.
    http://play.golang.org/p/9bWhx3G24a
    Examples of format strings, given n = 12345.6789:
    "#,###.##" => "12,345.67"
    @@ -100,45 +102,47 @@ func RenderFloat(format string, n float64) string {
    }
    }

    // Directive at index 0:
    // Must be a '+'
    // Raise an error if not the case
    // index: 0123456789
    // +0.000,000
    // +000,000.0
    // +0000.00
    // +0000
    if formatDirectiveIndices[0] == 0 {
    if formatDirectiveChars[formatDirectiveIndices[0]] != '+' {
    panic("RenderFloat(): invalid positive sign directive")
    if len(formatDirectiveIndices) > 0 {
    // Directive at index 0:
    // Must be a '+'
    // Raise an error if not the case
    // index: 0123456789
    // +0.000,000
    // +000,000.0
    // +0000.00
    // +0000
    if formatDirectiveIndices[0] == 0 {
    if formatDirectiveChars[formatDirectiveIndices[0]] != '+' {
    panic("RenderFloat(): invalid positive sign directive")
    }
    positiveStr = "+"
    formatDirectiveIndices = formatDirectiveIndices[1:]
    }
    positiveStr = "+"
    formatDirectiveIndices = formatDirectiveIndices[1:]
    }

    // Two directives:
    // First is thousands separator
    // Raise an error if not followed by 3-digit
    // 0123456789
    // 0.000,000
    // 000,000.00
    if len(formatDirectiveIndices) == 2 {
    if (formatDirectiveIndices[1] - formatDirectiveIndices[0]) != 4 {
    panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
    // Two directives:
    // First is thousands separator
    // Raise an error if not followed by 3-digit
    // 0123456789
    // 0.000,000
    // 000,000.00
    if len(formatDirectiveIndices) == 2 {
    if (formatDirectiveIndices[1] - formatDirectiveIndices[0]) != 4 {
    panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
    }
    thousandStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
    formatDirectiveIndices = formatDirectiveIndices[1:]
    }
    thousandStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
    formatDirectiveIndices = formatDirectiveIndices[1:]
    }

    // One directive:
    // Directive is decimal separator
    // The number of digit-specifier following the separator indicates wanted precision
    // 0123456789
    // 0.00
    // 000,0000
    if len(formatDirectiveIndices) == 1 {
    decimalStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
    precision = len(formatDirectiveChars) - formatDirectiveIndices[0] - 1
    // One directive:
    // Directive is decimal separator
    // The number of digit-specifier following the separator indicates wanted precision
    // 0123456789
    // 0.00
    // 000,0000
    if len(formatDirectiveIndices) == 1 {
    decimalStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
    precision = len(formatDirectiveChars) - formatDirectiveIndices[0] - 1
    }
    }
    }

  6. @gorhill gorhill revised this gist Apr 6, 2013. 1 changed file with 5 additions and 0 deletions.
    5 changes: 5 additions & 0 deletions render_number.go
    Original file line number Diff line number Diff line change
    @@ -86,6 +86,11 @@ func RenderFloat(format string, n float64) string {
    negativeStr := "-"

    if len(format) > 0 {
    // If there is an explicit format directive,
    // then default values are these:
    precision = 9
    thousandStr = ""

    // collect indices of meaningful formatting directives
    formatDirectiveChars := []rune(format)
    formatDirectiveIndices := make([]int, 0)
  7. @gorhill gorhill revised this gist Apr 2, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion render_number.go
    Original file line number Diff line number Diff line change
    @@ -14,7 +14,7 @@ Usage: s := RenderFloat(format, n)
    The format parameter tells how to render the number n.
    Examples, given n = 12345.6789:
    Examples of format strings, given n = 12345.6789:
    "#,###.##" => "12,345.67"
    "#,###." => "12,345"
  8. @gorhill gorhill revised this gist Apr 2, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion render_number.go
    Original file line number Diff line number Diff line change
    @@ -141,7 +141,7 @@ func RenderFloat(format string, n float64) string {
    var signStr string
    if n >= 0.000000001 {
    signStr = positiveStr
    } else if n < -0.000000001 {
    } else if n <= -0.000000001 {
    signStr = negativeStr
    n = -n
    } else {
  9. @gorhill gorhill revised this gist Apr 1, 2013. 1 changed file with 134 additions and 134 deletions.
    268 changes: 134 additions & 134 deletions render_number.go
    Original file line number Diff line number Diff line change
    @@ -38,146 +38,146 @@ import (
    )

    var renderFloatPrecisionMultipliers = [10]float64{
    1,
    10,
    100,
    1000,
    10000,
    100000,
    1000000,
    10000000,
    100000000,
    1000000000,
    1,
    10,
    100,
    1000,
    10000,
    100000,
    1000000,
    10000000,
    100000000,
    1000000000,
    }

    var renderFloatPrecisionRounders = [10]float64{
    0.5,
    0.05,
    0.005,
    0.0005,
    0.00005,
    0.000005,
    0.0000005,
    0.00000005,
    0.000000005,
    0.0000000005,
    0.5,
    0.05,
    0.005,
    0.0005,
    0.00005,
    0.000005,
    0.0000005,
    0.00000005,
    0.000000005,
    0.0000000005,
    }

    func RenderFloat(format string, n float64) string {
    // Special cases:
    // NaN = "NaN"
    // +Inf = "+Infinity"
    // -Inf = "-Infinity"
    if math.IsNaN(n) {
    return "NaN"
    }
    if n > math.MaxFloat64 {
    return "Infinity"
    }
    if n < -math.MaxFloat64 {
    return "-Infinity"
    }

    // default format
    precision := 2
    decimalStr := "."
    thousandStr := ","
    positiveStr := ""
    negativeStr := "-"

    if len(format) > 0 {
    // collect indices of meaningful formatting directives
    formatDirectiveChars := []rune(format)
    formatDirectiveIndices := make([]int, 0)
    for i, char := range formatDirectiveChars {
    if char != '#' && char != '0' {
    formatDirectiveIndices = append(formatDirectiveIndices, i)
    }
    }

    // Directive at index 0:
    // Must be a '+'
    // Raise an error if not the case
    // index: 0123456789
    // +0.000,000
    // +000,000.0
    // +0000.00
    // +0000
    if formatDirectiveIndices[0] == 0 {
    if formatDirectiveChars[formatDirectiveIndices[0]] != '+' {
    panic("gncNumberFormat(): invalid positive sign directive")
    }
    positiveStr = "+"
    formatDirectiveIndices = formatDirectiveIndices[1:]
    }

    // Two directives:
    // First is thousands separator
    // Raise an error if not followed by 3-digit
    // 0123456789
    // 0.000,000
    // 000,000.00
    if len(formatDirectiveIndices) == 2 {
    if (formatDirectiveIndices[1] - formatDirectiveIndices[0]) != 4 {
    panic("gncNumberFormat(): thousands separator directive must be followed by 3 digit-specifiers")
    }
    thousandStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
    formatDirectiveIndices = formatDirectiveIndices[1:]
    }

    // One directive:
    // Directive is decimal separator
    // The number of digit-specifier following the separator indicates wanted precision
    // 0123456789
    // 0.00
    // 000,0000
    if len(formatDirectiveIndices) == 1 {
    decimalStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
    precision = len(formatDirectiveChars) - formatDirectiveIndices[0] - 1
    }
    }

    // generate sign part
    var signStr string
    if n >= 0.000000001 {
    signStr = positiveStr
    } else if n <= -0.000000001 {
    signStr = negativeStr
    n = -n
    } else {
    signStr = ""
    n = 0.0
    }

    // split number into integer and fractional parts
    intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])

    // generate integer part string
    intStr := strconv.Itoa(int(intf))

    // add thousand separator if required
    if len(thousandStr) > 0 {
    for i := len(intStr); i > 3; {
    i -= 3
    intStr = intStr[:i] + thousandStr + intStr[i:]
    }
    }

    // no fractional part, we can leave now
    if precision == 0 {
    return signStr + intStr
    }

    // generate fractional part
    fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
    // may need padding
    if len(fracStr) < precision {
    fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
    }

    return signStr + intStr + decimalStr + fracStr
    // Special cases:
    // NaN = "NaN"
    // +Inf = "+Infinity"
    // -Inf = "-Infinity"
    if math.IsNaN(n) {
    return "NaN"
    }
    if n > math.MaxFloat64 {
    return "Infinity"
    }
    if n < -math.MaxFloat64 {
    return "-Infinity"
    }

    // default format
    precision := 2
    decimalStr := "."
    thousandStr := ","
    positiveStr := ""
    negativeStr := "-"

    if len(format) > 0 {
    // collect indices of meaningful formatting directives
    formatDirectiveChars := []rune(format)
    formatDirectiveIndices := make([]int, 0)
    for i, char := range formatDirectiveChars {
    if char != '#' && char != '0' {
    formatDirectiveIndices = append(formatDirectiveIndices, i)
    }
    }

    // Directive at index 0:
    // Must be a '+'
    // Raise an error if not the case
    // index: 0123456789
    // +0.000,000
    // +000,000.0
    // +0000.00
    // +0000
    if formatDirectiveIndices[0] == 0 {
    if formatDirectiveChars[formatDirectiveIndices[0]] != '+' {
    panic("RenderFloat(): invalid positive sign directive")
    }
    positiveStr = "+"
    formatDirectiveIndices = formatDirectiveIndices[1:]
    }

    // Two directives:
    // First is thousands separator
    // Raise an error if not followed by 3-digit
    // 0123456789
    // 0.000,000
    // 000,000.00
    if len(formatDirectiveIndices) == 2 {
    if (formatDirectiveIndices[1] - formatDirectiveIndices[0]) != 4 {
    panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
    }
    thousandStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
    formatDirectiveIndices = formatDirectiveIndices[1:]
    }

    // One directive:
    // Directive is decimal separator
    // The number of digit-specifier following the separator indicates wanted precision
    // 0123456789
    // 0.00
    // 000,0000
    if len(formatDirectiveIndices) == 1 {
    decimalStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
    precision = len(formatDirectiveChars) - formatDirectiveIndices[0] - 1
    }
    }

    // generate sign part
    var signStr string
    if n >= 0.000000001 {
    signStr = positiveStr
    } else if n < -0.000000001 {
    signStr = negativeStr
    n = -n
    } else {
    signStr = ""
    n = 0.0
    }

    // split number into integer and fractional parts
    intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])

    // generate integer part string
    intStr := strconv.Itoa(int(intf))

    // add thousand separator if required
    if len(thousandStr) > 0 {
    for i := len(intStr); i > 3; {
    i -= 3
    intStr = intStr[:i] + thousandStr + intStr[i:]
    }
    }

    // no fractional part, we can leave now
    if precision == 0 {
    return signStr + intStr
    }

    // generate fractional part
    fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
    // may need padding
    if len(fracStr) < precision {
    fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
    }

    return signStr + intStr + decimalStr + fracStr
    }

    func RenderInteger(format string, n int) string {
    return RenderFloat(format, float64(n))
    }
    return RenderFloat(format, float64(n))
    }
  10. @gorhill gorhill revised this gist Apr 1, 2013. 1 changed file with 10 additions and 4 deletions.
    14 changes: 10 additions & 4 deletions render_number.go
    Original file line number Diff line number Diff line change
    @@ -3,15 +3,18 @@
    Author: https://github.com/gorhill
    Source: https://gist.github.com/gorhill/5285193
    A Go function to render a number to a string based on the following user-specified criteria:
    A Go function to render a number to a string based on
    the following user-specified criteria:
    * thousands separator
    * decimal separator
    * decimal precision
    Usage: s := RenderFloat(format, n)
    The format parameter tells how to render the number n. Examples, given n = 12345.6789:
    The format parameter tells how to render the number n.
    Examples, given n = 12345.6789:
    "#,###.##" => "12,345.67"
    "#,###." => "12,345"
    @@ -20,9 +23,12 @@ The format parameter tells how to render the number n. Examples, given n = 12345
    "#.###,###### => 12.345,678900
    "" (aka default format) => 12,345.67
    The highest precision allowed is 9 digits after the decimal symbol. There is also a version for integer number, RenderInteger(), which is convenient for calls within template.
    The highest precision allowed is 9 digits after the decimal symbol.
    There is also a version for integer number, RenderInteger(),
    which is convenient for calls within template.
    I didn't feel it was worth to publish a library just for this piece of code, hence the snippet. Feel free to reuse as you wish.
    I didn't feel it was worth to publish a library just for this piece
    of code, hence the snippet. Feel free to reuse as you wish.
    */

  11. @gorhill gorhill revised this gist Apr 1, 2013. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions render_number.go
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,8 @@
    /*
    Author: https://github.com/gorhill
    Source: https://gist.github.com/gorhill/5285193
    A Go function to render a number to a string based on the following user-specified criteria:
    * thousands separator
  12. @gorhill gorhill revised this gist Apr 1, 2013. 1 changed file with 25 additions and 0 deletions.
    25 changes: 25 additions & 0 deletions render_number.go
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,28 @@
    /*
    A Go function to render a number to a string based on the following user-specified criteria:
    * thousands separator
    * decimal separator
    * decimal precision
    Usage: s := RenderFloat(format, n)
    The format parameter tells how to render the number n. Examples, given n = 12345.6789:
    "#,###.##" => "12,345.67"
    "#,###." => "12,345"
    "#,###" => "12345,678"
    "#\u202F###,##" => "12 345,67"
    "#.###,###### => 12.345,678900
    "" (aka default format) => 12,345.67
    The highest precision allowed is 9 digits after the decimal symbol. There is also a version for integer number, RenderInteger(), which is convenient for calls within template.
    I didn't feel it was worth to publish a library just for this piece of code, hence the snippet. Feel free to reuse as you wish.
    */

    import (
    "math"
    "strconv"
  13. @gorhill gorhill revised this gist Apr 1, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion render_number.go
    Original file line number Diff line number Diff line change
    @@ -107,7 +107,7 @@ func RenderFloat(format string, n float64) string {
    var signStr string
    if n >= 0.000000001 {
    signStr = positiveStr
    } else if n < -0.000000001 {
    } else if n <= -0.000000001 {
    signStr = negativeStr
    n = -n
    } else {
  14. @gorhill gorhill created this gist Apr 1, 2013.
    149 changes: 149 additions & 0 deletions render_number.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,149 @@
    import (
    "math"
    "strconv"
    )

    var renderFloatPrecisionMultipliers = [10]float64{
    1,
    10,
    100,
    1000,
    10000,
    100000,
    1000000,
    10000000,
    100000000,
    1000000000,
    }

    var renderFloatPrecisionRounders = [10]float64{
    0.5,
    0.05,
    0.005,
    0.0005,
    0.00005,
    0.000005,
    0.0000005,
    0.00000005,
    0.000000005,
    0.0000000005,
    }

    func RenderFloat(format string, n float64) string {
    // Special cases:
    // NaN = "NaN"
    // +Inf = "+Infinity"
    // -Inf = "-Infinity"
    if math.IsNaN(n) {
    return "NaN"
    }
    if n > math.MaxFloat64 {
    return "Infinity"
    }
    if n < -math.MaxFloat64 {
    return "-Infinity"
    }

    // default format
    precision := 2
    decimalStr := "."
    thousandStr := ","
    positiveStr := ""
    negativeStr := "-"

    if len(format) > 0 {
    // collect indices of meaningful formatting directives
    formatDirectiveChars := []rune(format)
    formatDirectiveIndices := make([]int, 0)
    for i, char := range formatDirectiveChars {
    if char != '#' && char != '0' {
    formatDirectiveIndices = append(formatDirectiveIndices, i)
    }
    }

    // Directive at index 0:
    // Must be a '+'
    // Raise an error if not the case
    // index: 0123456789
    // +0.000,000
    // +000,000.0
    // +0000.00
    // +0000
    if formatDirectiveIndices[0] == 0 {
    if formatDirectiveChars[formatDirectiveIndices[0]] != '+' {
    panic("gncNumberFormat(): invalid positive sign directive")
    }
    positiveStr = "+"
    formatDirectiveIndices = formatDirectiveIndices[1:]
    }

    // Two directives:
    // First is thousands separator
    // Raise an error if not followed by 3-digit
    // 0123456789
    // 0.000,000
    // 000,000.00
    if len(formatDirectiveIndices) == 2 {
    if (formatDirectiveIndices[1] - formatDirectiveIndices[0]) != 4 {
    panic("gncNumberFormat(): thousands separator directive must be followed by 3 digit-specifiers")
    }
    thousandStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
    formatDirectiveIndices = formatDirectiveIndices[1:]
    }

    // One directive:
    // Directive is decimal separator
    // The number of digit-specifier following the separator indicates wanted precision
    // 0123456789
    // 0.00
    // 000,0000
    if len(formatDirectiveIndices) == 1 {
    decimalStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
    precision = len(formatDirectiveChars) - formatDirectiveIndices[0] - 1
    }
    }

    // generate sign part
    var signStr string
    if n >= 0.000000001 {
    signStr = positiveStr
    } else if n < -0.000000001 {
    signStr = negativeStr
    n = -n
    } else {
    signStr = ""
    n = 0.0
    }

    // split number into integer and fractional parts
    intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])

    // generate integer part string
    intStr := strconv.Itoa(int(intf))

    // add thousand separator if required
    if len(thousandStr) > 0 {
    for i := len(intStr); i > 3; {
    i -= 3
    intStr = intStr[:i] + thousandStr + intStr[i:]
    }
    }

    // no fractional part, we can leave now
    if precision == 0 {
    return signStr + intStr
    }

    // generate fractional part
    fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
    // may need padding
    if len(fracStr) < precision {
    fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
    }

    return signStr + intStr + decimalStr + fracStr
    }

    func RenderInteger(format string, n int) string {
    return RenderFloat(format, float64(n))
    }