class Numeric

Adds the ability to create various readable representations of numbers to the Numeric Class.

Constants

BINARY_PREFIXES

Binary Prefix symbols for positive exponents.

MAX_NREADABLE_EXP

Length of symbol arrays - 1.

NUMBER_NAMING

English short scale names of numeric values. If you need a different scale or language, just replace the content of this array. Make sure it has MAX_NREADABLE_EXP + 1 fields.

SI_PREFIXES_BIG

SI-Prefix symbols for positive exponents.

SI_PREFIXES_SMALL

SI-Prefix symbols for negative exponents.

Public Instance Methods

bin_prefixed( precision = 1 ) click to toggle source

Creates a representation of the number with a binary prefix attached. @param precision [Integer] maximum precision. Must be >= 0. @return [String] the formatted number. @example

1024.bin_prefixed #=> "1Ki"
1_048_576.bin_prefixed + "B" #=> "1MiB"
# File lib/nreadable.rb, line 116
def bin_prefixed( precision = 1 )
  raise ArgumentError, "negative precision" if precision < 0
  return self.to_s if self < 1024 and self > -1024
  return self.to_s if self.is_a? Float and !self.finite?

  number, exponent = base_and_exponent(1024)
  result = nreadable_base_s( number, precision )
  result + BINARY_PREFIXES[exponent]
end
delimited( delimiter = ',', separator = '.' ) click to toggle source

Creates a better readable representation of the number by adding thousands separators. @param delimiter [String] the character(s) to use as the thousands

separator.

@param separator [String] the character(s) to use as the decimal point. @return [String] the number with thousands separator. @example

12345678.readable #=> "12,345,678"
# File lib/nreadable.rb, line 33
def delimited( delimiter = ',', separator = '.' )
  return self.to_s if self.is_a? Rational
  return self.to_s if self.is_a? Float and !self.finite?

  negative = self < 0
  result   = self.abs.to_s
  length   = result.length
  rounds   = 0
  decimal_position = result.index('.')

  pointer = if decimal_position
    result[decimal_position] = separator
    decimal_position - length - 4
  else
    -4
  end

  while pointer.abs <= length + rounds
    result.insert(pointer, delimiter)
    pointer -= 4
    rounds  += 1
  end

  result = "-" + result if negative
  result
end
named( precision = 1 ) click to toggle source

Creates a representation of the number using the short scale large-number naming system with english words. You can change this by modifying the NUMBER_NAMING constant. @param precision [Integer] maximum precision. Must be >= 0. @return [String] the formatted number. @example

2000.named #=> "2 thousand"
2_310_000.named #=> "2.3 million"
# File lib/nreadable.rb, line 136
def named( precision = 1 )
  raise ArgumentError, "negative precision" if precision < 0
  return self.to_s if self < 1000 and self > -1000
  return self.to_s if self.is_a? Float and !self.finite?

  number, exponent = base_and_exponent(1000)
  result = nreadable_base_s( number, precision )
  "#{result} #{NUMBER_NAMING[exponent]}"
end
scientific( precision = 6 ) click to toggle source

Creates a scientific representation of the number. An exponential notation is used if the number is >= 1000 or < 0.01. @param precision [Integer] the maximum precision. Only applies if the

exponential notation is used. Must be >= 0

@return [String] the formatted number. @example

12.55.scientific #=> "12.55"
10000.scientific #=> "1e+04"
12345.scientific #=> "1.2345e+04"
# File lib/nreadable.rb, line 71
def scientific( precision = 6 )
  raise ArgumentError, "negative precision" if precision < 0
  return self.to_s if (self < 1000 and self >= 0.01) or (self == 0) or
      (self > -1000 and self <= -0.01)
  return self.to_s if self.is_a? Float and !self.finite?

  result = sprintf("%.#{ precision }e", self)
  position = result.index('e') - 1
  
  strip_insignificant_digits( result, position )
end
si_prefixed( precision = 6 ) click to toggle source

Creates a representation of the number with a SI prefix attached. @param precision [Integer] maximum precision. Must be >= 0. @return [String] the formatted number. @example

0.0000012.si_prefixed #=> "1.2µ"
1000.si_prefixed #=> "1k"
# File lib/nreadable.rb, line 91
def si_prefixed( precision = 6 )
  raise ArgumentError, "negative precision" if precision < 0
  return self.to_s if (self < 1000 and self >= 1) or (self == 0) or
      (self > -1000 and self <= -1)
  return self.to_s if self.is_a? Float and !self.finite?

  number, exponent = base_and_exponent(1000)
  unit = if exponent >= 0
    SI_PREFIXES_BIG[exponent]
  else
    SI_PREFIXES_SMALL[exponent.abs]
  end

  result = nreadable_base_s( number, precision )
  result + unit
end

Private Instance Methods

base_and_exponent( base ) click to toggle source

calculates the base and the exponent of self and returns it in an array. @param base [Integer] base to use in the calculation.

# File lib/nreadable.rb, line 150
def base_and_exponent( base )
  return [0, 0] if self == 0

  f = self.to_f
  exponent = (Math.log(f.abs) / Math.log(base)).floor
  if exponent > MAX_NREADABLE_EXP
    exponent = MAX_NREADABLE_EXP
    number = self / (base ** exponent)
  elsif exponent < -MAX_NREADABLE_EXP
    exponent = -MAX_NREADABLE_EXP
    number = self / (base ** exponent)
  else
    number = (f / (base ** exponent)).round(8) #round to counter float errors
  end
  
  [number, exponent]
end
nreadable_base_s( number, precision ) click to toggle source

converts number to string with given precision and thousands separator.

# File lib/nreadable.rb, line 169
def nreadable_base_s( number, precision )
  number = number.round(precision) if number.is_a? Float
  result = number.delimited
  strip_insignificant_digits(result) if number.is_a? Float

  result
end
strip_insignificant_digits( string, index = nil ) click to toggle source

strips trailing zeros and the . if it’s the last character

# File lib/nreadable.rb, line 178
def strip_insignificant_digits( string, index = nil )
  index = string.length - 1 if index.nil?

  while string[index] == '0' 
    string[index] = ''
    index -= 1
  end

  if string[index] == '.'
    string[index] = ''
  end

  string
end