webmcp
view framework/env/format/decimal.lua @ 155:185e944182cb
Better C macros for null-marker in JSON library
| author | jbe | 
|---|---|
| date | Thu Jul 31 03:18:04 2014 +0200 (2014-07-31) | 
| parents | 9fdfb27f8e67 | 
| children | 
 line source
     1 --[[--
     2 text =                             -- text with the value formatted as decimal number
     3 format.decimal(
     4   value,                           -- a number, a fraction or nil
     5   {
     6     nil_as        = nil_text,      -- text to be returned for a nil value
     7     digits        = digits,        -- digits before decimal point
     8     precision     = precision,     -- digits after decimal point
     9     decimal_shift = decimal_shift  -- divide the value by 10^decimal_shift (setting true uses precision)
    10   }
    11 )
    13 Formats a (floating point) number or a fraction as a decimal number. If a 'digits' option is set, the number of digits before the decimal point is increased up to the given count by preceding it with zeros. The digits after the decimal point are adjusted by the 'precision' parameter. The 'decimal_shift' parameter is useful, when fixed precision decimal numbers are stored as integers, as the given value will be divided by 10 to the power of the 'decimal_shift' value prior to formatting. Setting 'decimal_shift' to true will copy the value for 'precision'.
    15 --]]--
    17 function format.decimal(value, options)
    18   -- TODO: more features
    19   local options = options or {}
    20   local special_chars = charset.get_data().special_chars
    21   local f
    22   if value == nil then
    23     return options.nil_as or ""
    24   elseif atom.has_type(value, atom.number) then
    25     f = value
    26   elseif atom.has_type(value, atom.fraction) then
    27     f = value.float
    28   else
    29     error("Value passed to format.decimal(...) is neither a number nor a fraction nor nil.")
    30   end
    31   local digits = options.digits
    32   local precision = options.precision or 0
    33   local decimal_shift = options.decimal_shift or 0
    34   if decimal_shift == true then
    35     decimal_shift = precision
    36   end
    37   f = f / 10 ^ decimal_shift
    38   local negative
    39   local absolute
    40   if f < 0 then
    41     absolute = -f
    42     negative = true
    43   else
    44     absolute = f
    45     negative = false
    46   end
    47   absolute = absolute + 0.5 / 10 ^ precision
    48   local int = math.floor(absolute)
    49   if not atom.is_integer(int) then
    50     if f > 0 then
    51       return "+" .. special_chars.inf_sign
    52     elseif f < 0 then
    53       return minus_sign .. special_chars.inf_sign
    54     else
    55       return "NaN"
    56     end
    57   end
    58   local int_str = tostring(int)
    59   if digits then
    60     while #int_str < digits do
    61       int_str = "0" .. int_str
    62     end
    63   end
    64   if precision > 0 then
    65     local decimal_point =
    66       options.decimal_point or
    67       locale.get('decimal_point') or '.'
    68     local frac_str = tostring(math.floor((absolute - int) * 10 ^ precision))
    69     while #frac_str < precision do
    70       frac_str = "0" .. frac_str
    71     end
    72     assert(#frac_str == precision, "Assertion failed in format.float(...).")  -- should not happen
    73     if negative then
    74       return special_chars.minus_sign .. int_str .. decimal_point .. frac_str
    75     elseif options.show_plus then
    76       return "+" .. int_str .. decimal_point .. frac_str
    77     else
    78       return int_str .. decimal_point .. frac_str
    79     end
    80   else
    81     if negative then
    82       return special_chars.minus_sign .. int
    83     elseif options.show_plus then
    84       return "+" .. int_str
    85     else
    86       return int_str
    87     end
    88   end
    89 end
