gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

number.go (4320B)


      1 package humanize
      2 
      3 /*
      4 Slightly adapted from the source to fit go-humanize.
      5 
      6 Author: https://github.com/gorhill
      7 Source: https://gist.github.com/gorhill/5285193
      8 
      9 */
     10 
     11 import (
     12 	"math"
     13 	"strconv"
     14 )
     15 
     16 var (
     17 	renderFloatPrecisionMultipliers = [...]float64{
     18 		1,
     19 		10,
     20 		100,
     21 		1000,
     22 		10000,
     23 		100000,
     24 		1000000,
     25 		10000000,
     26 		100000000,
     27 		1000000000,
     28 	}
     29 
     30 	renderFloatPrecisionRounders = [...]float64{
     31 		0.5,
     32 		0.05,
     33 		0.005,
     34 		0.0005,
     35 		0.00005,
     36 		0.000005,
     37 		0.0000005,
     38 		0.00000005,
     39 		0.000000005,
     40 		0.0000000005,
     41 	}
     42 )
     43 
     44 // FormatFloat produces a formatted number as string based on the following user-specified criteria:
     45 // * thousands separator
     46 // * decimal separator
     47 // * decimal precision
     48 //
     49 // Usage: s := RenderFloat(format, n)
     50 // The format parameter tells how to render the number n.
     51 //
     52 // See examples: http://play.golang.org/p/LXc1Ddm1lJ
     53 //
     54 // Examples of format strings, given n = 12345.6789:
     55 // "#,###.##" => "12,345.67"
     56 // "#,###." => "12,345"
     57 // "#,###" => "12345,678"
     58 // "#\u202F###,##" => "12 345,68"
     59 // "#.###,###### => 12.345,678900
     60 // "" (aka default format) => 12,345.67
     61 //
     62 // The highest precision allowed is 9 digits after the decimal symbol.
     63 // There is also a version for integer number, FormatInteger(),
     64 // which is convenient for calls within template.
     65 func FormatFloat(format string, n float64) string {
     66 	// Special cases:
     67 	//   NaN = "NaN"
     68 	//   +Inf = "+Infinity"
     69 	//   -Inf = "-Infinity"
     70 	if math.IsNaN(n) {
     71 		return "NaN"
     72 	}
     73 	if n > math.MaxFloat64 {
     74 		return "Infinity"
     75 	}
     76 	if n < (0.0 - math.MaxFloat64) {
     77 		return "-Infinity"
     78 	}
     79 
     80 	// default format
     81 	precision := 2
     82 	decimalStr := "."
     83 	thousandStr := ","
     84 	positiveStr := ""
     85 	negativeStr := "-"
     86 
     87 	if len(format) > 0 {
     88 		format := []rune(format)
     89 
     90 		// If there is an explicit format directive,
     91 		// then default values are these:
     92 		precision = 9
     93 		thousandStr = ""
     94 
     95 		// collect indices of meaningful formatting directives
     96 		formatIndx := []int{}
     97 		for i, char := range format {
     98 			if char != '#' && char != '0' {
     99 				formatIndx = append(formatIndx, i)
    100 			}
    101 		}
    102 
    103 		if len(formatIndx) > 0 {
    104 			// Directive at index 0:
    105 			//   Must be a '+'
    106 			//   Raise an error if not the case
    107 			// index: 0123456789
    108 			//        +0.000,000
    109 			//        +000,000.0
    110 			//        +0000.00
    111 			//        +0000
    112 			if formatIndx[0] == 0 {
    113 				if format[formatIndx[0]] != '+' {
    114 					panic("RenderFloat(): invalid positive sign directive")
    115 				}
    116 				positiveStr = "+"
    117 				formatIndx = formatIndx[1:]
    118 			}
    119 
    120 			// Two directives:
    121 			//   First is thousands separator
    122 			//   Raise an error if not followed by 3-digit
    123 			// 0123456789
    124 			// 0.000,000
    125 			// 000,000.00
    126 			if len(formatIndx) == 2 {
    127 				if (formatIndx[1] - formatIndx[0]) != 4 {
    128 					panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
    129 				}
    130 				thousandStr = string(format[formatIndx[0]])
    131 				formatIndx = formatIndx[1:]
    132 			}
    133 
    134 			// One directive:
    135 			//   Directive is decimal separator
    136 			//   The number of digit-specifier following the separator indicates wanted precision
    137 			// 0123456789
    138 			// 0.00
    139 			// 000,0000
    140 			if len(formatIndx) == 1 {
    141 				decimalStr = string(format[formatIndx[0]])
    142 				precision = len(format) - formatIndx[0] - 1
    143 			}
    144 		}
    145 	}
    146 
    147 	// generate sign part
    148 	var signStr string
    149 	if n >= 0.000000001 {
    150 		signStr = positiveStr
    151 	} else if n <= -0.000000001 {
    152 		signStr = negativeStr
    153 		n = -n
    154 	} else {
    155 		signStr = ""
    156 		n = 0.0
    157 	}
    158 
    159 	// split number into integer and fractional parts
    160 	intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])
    161 
    162 	// generate integer part string
    163 	intStr := strconv.FormatInt(int64(intf), 10)
    164 
    165 	// add thousand separator if required
    166 	if len(thousandStr) > 0 {
    167 		for i := len(intStr); i > 3; {
    168 			i -= 3
    169 			intStr = intStr[:i] + thousandStr + intStr[i:]
    170 		}
    171 	}
    172 
    173 	// no fractional part, we can leave now
    174 	if precision == 0 {
    175 		return signStr + intStr
    176 	}
    177 
    178 	// generate fractional part
    179 	fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
    180 	// may need padding
    181 	if len(fracStr) < precision {
    182 		fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
    183 	}
    184 
    185 	return signStr + intStr + decimalStr + fracStr
    186 }
    187 
    188 // FormatInteger produces a formatted number as string.
    189 // See FormatFloat.
    190 func FormatInteger(format string, n int) string {
    191 	return FormatFloat(format, float64(n))
    192 }