Class: Numeric

Inherits:
Object show all
Defined in:
lib/epitools/numwords.rb,
lib/epitools/core_ext/numbers.rb,
lib/epitools/core_ext/truthiness.rb

Overview

>> 1.27.million.billion

=> 1_270_000_000_000_000

>> 12873218731.to_words
=> "twelve billion, eight-hundred and seventy-three million, two-hundred and eighteen thousand, seven-hundred and thirty-one"

Works on numbers up to a googol!

Constant Summary collapse

NAMES_SMALL =

< 20

[
  "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
]
NAMES_MEDIUM =

20-90

[
  "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety"
]
NAMES_LARGE =

>= 100

[
  "thousand", "million", "billion", "trillion", "quadrillion", "quintillion", "sextillion", "septillion", "octillion", "nonillion", "decillion", "undecillion", "duodecillion", "tredecillion", "quattuordecillion", "quindecillion", "sexdecillion", "septendecillion", "octodecillion", "novemdecillion", "vigintillion", "unvigintillion", "duovigintillion", "trevigintillion", "quattuorvigintillion", "quinvigintillion", "sexvigintillion", "septenvigintillion", "octovigintillion", "novemvigintillion", "trigintillion", "untrigintillion", "duotrigintillion"
]
BYTE_SIZE_TABLE =
{
  # power    # units
  0          => "",
  1          => "KB",
  2          => "MB",
  3          => "GB",
  4          => "TB",
  5          => "PB",
  6          => "EB",
  7          => "ZB",
  8          => "YB",
}

Instance Method Summary collapse

Instance Method Details

#agoObject


68
69
70
# File 'lib/epitools/core_ext/numbers.rb', line 68

def ago
  Time.now - self
end

#choose(r) ⇒ Object Also known as: combinations

Combinations: compute “n choose r” (self.choose®)

This represents number of ways to pick “r” items from a collection of “self” items (where the order of the items doesn't matter, and items can't be repeated.)

eg: 49.choose(6) is how many ways can we pick 6 lottery numbers from a set of 49.

Formula: n! / (r! * (n-r)!) == n * n-1 * … * n-r / r * r-1 * … * 2


135
136
137
# File 'lib/epitools/core_ext/numbers.rb', line 135

def choose(r)
  (self-r+1..self).reduce(:*) / (2..r).reduce(:*)
end

#clamp(range) ⇒ Object

Clamp the number to a specific range

Examples:

234234234523.clamp(0..100)   #=> 100
12.clamp(0..100)             #=> 12
-38817112.clamp(0..100)      #=> 0

36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/epitools/core_ext/numbers.rb', line 36

def clamp(range)
  if self < range.first
    range.first
  elsif self >= range.last
    if range.exclude_end?
      range.last - 1
    else
      range.last
    end
  else
    self
  end
end

#commatize(char = ",") ⇒ Object

Convert this number to a string, adding commas between each group of 3 digits.

(The “char” argument is optional, and specifies what character to use in between

each group of numbers.)

12
13
14
15
16
17
18
19
# File 'lib/epitools/core_ext/numbers.rb', line 12

def commatize(char=",")
  str = self.is_a?(BigDecimal) ? to_s("F") : to_s

  int, frac = str.split(".")
  int = int.gsub /(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/, "\\1#{char}\\2"

  frac ? "#{int}.#{frac}" : int
end

#from_nowObject


72
73
74
# File 'lib/epitools/core_ext/numbers.rb', line 72

def from_now
  Time.now + self
end

#human_bytes(decimals = 0) ⇒ Object Also known as: human_size


201
202
203
204
205
206
# File 'lib/epitools/core_ext/numbers.rb', line 201

def human_bytes(decimals=0)
  power = self.log(1024).floor
  base  = 1024.0 ** power
  units = BYTE_SIZE_TABLE[power]
  "#{(self / base).round(decimals)}#{units}"
end

#lnObject


120
121
122
# File 'lib/epitools/core_ext/numbers.rb', line 120

def ln
  Math.log(self)
end

#log(n = nil) ⇒ Object


168
169
170
171
172
173
174
# File 'lib/epitools/core_ext/numbers.rb', line 168

def log(n=nil)
  if n
    Math.log(self) / Math.log(n)
  else
    Math.log(self)
  end
end

#mulmod(n) ⇒ Object

Multiply self by n, returning the integer product and the floating point remainder.


158
159
160
161
162
163
# File 'lib/epitools/core_ext/numbers.rb', line 158

def mulmod(n)
  prod    = self * n
  intprod = prod.to_i

  [intprod, prod % intprod]
end

#number?Boolean


51
# File 'lib/epitools/core_ext/truthiness.rb', line 51

def number?; true; end

#perms(r) ⇒ Object Also known as: permutations

Permutations: compute “n P r”

This represents number of ways to pick “r” items from a collection of “self” items (where the order of the items DOES matter, and items can't be repeated.)

eg: 23.perm(3) is how many ways 23 people can win 1st, 2nd and 3rd place in a race.

Formula: n! / (n - r)!


150
151
152
# File 'lib/epitools/core_ext/numbers.rb', line 150

def perms(r)
  (self-r+1..self).reduce(:*)
end

#things(&block) ⇒ Object

If `n.times` is like `each`, `n.things` is like `map`. Return


79
80
81
82
83
84
85
# File 'lib/epitools/core_ext/numbers.rb', line 79

def things(&block)
  if block_given?
    Array.new(self, &block)
  else
    (0...self).to_a
  end
end

#to_hmsObject

Convert seconds to hours:minutes:seconds (hours is dropped if it's zero)


213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/epitools/core_ext/numbers.rb', line 213

def to_hms
  seconds = self

  days, seconds    = seconds.divmod(86400)
  hours, seconds   = seconds.divmod(3600)
  minutes, seconds = seconds.divmod(60)
  seconds, frac    = seconds.divmod(1)

  result = "%0.2d:%0.2d" % [minutes,seconds]
  result = ("%0.2d:" % hours) + result   if hours > 0 or days > 0
  result = ("%0.2d:" % days)  + result   if days > 0
  result += ("." + frac.round(2).to_s.split(".").last) if frac > 0

  result
end

#to_hms_in_wordsObject


229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/epitools/core_ext/numbers.rb', line 229

def to_hms_in_words
  seconds = self

  days, seconds    = seconds.divmod(86400)
  hours, seconds   = seconds.divmod(3600)
  minutes, seconds = seconds.divmod(60)
  seconds, frac    = seconds.divmod(1)

  result = "#{seconds} sec"
  result = "#{minutes} min, " + result if minutes > 0
  result = "#{"hour".amount(hours)}, " + result if hours > 0 or days > 0
  result = "#{"day".amount(days)}, "   + result if days > 0
  # result += ("." + frac.round(2).to_s.split(".").last) if frac > 0

  result
end

#to_wordsObject

Convert this number to words (eg: 69 => 'sixty-nine'). Works with numbers up to a googol (10^100).


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/epitools/numwords.rb', line 39

def to_words
  if is_a? Integer
    num = self
  else
    num = self.to_i
  end

  if (n = num.to_s.size) > 102
    return "more than a googol! (#{n} digits)"
  end

  whole_thing = []

  triplets = num.commatize.split(',')
  num_triplets = triplets.size

  triplets.each_with_index do |triplet, i|
    next if triplet.to_i == 0

    result = []

    tens, hunds = nil, nil

    digits = triplet.chars.to_a

    raise "Error: Not a triplet: #{triplet}" if digits.size > 3 or digits.size < 1

    if digits.size == 3
      digit = digits.shift.to_i
      hunds = NAMES_SMALL[digit] + "-hundred" if digit > 0
      digits.shift if digits.first == '0'
    end

    if digits.size == 2
      n = digits.join('').to_i

      if n > 0 and n < 20
        tens = NAMES_SMALL[n]
      elsif n > 0
        tens = NAMES_MEDIUM[digits.shift.to_i - 2]
        if digits.first != '0'
          tens += "-" + NAMES_SMALL[digits.shift.to_i]
        else
          digits.shift
        end
      end
    end

    if digits.size == 1
      n = digits.join('').to_i
      tens = NAMES_SMALL[n] if n > 0
    end

    if hunds
      if tens
        result << "#{hunds} and #{tens}"
      else
        result << hunds
      end
    else
      result << tens if tens
    end

    magnitude = (num_triplets - i)
    result << NAMES_LARGE[magnitude-2] if magnitude > 1

    whole_thing << result.join(' ') if result.any?
  end

  whole_thing.join ', '
end

#truthy?Boolean


49
# File 'lib/epitools/core_ext/truthiness.rb', line 49

def truthy?; self > 0; end

#underscorizeObject

Convert this number to a string, adding underscores between each group of 3 digits.


24
25
26
# File 'lib/epitools/core_ext/numbers.rb', line 24

def underscorize
  commatize("_")
end