...

Source file src/github.com/dustin/go-humanize/number.go

Documentation: github.com/dustin/go-humanize

     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  }
   193  

View as plain text