Module: FatCore::Numeric

Included in:
Numeric
Defined in:
lib/fat_core/numeric.rb

Instance Method Summary collapse

Instance Method Details

#commas(places = nil) ⇒ String

Convert this number into a string and insert grouping commas into the whole number part and round the decimal part to places decimal places, with the default number of places being zero for an integer and 4 for a non-integer. The fractional part is padded with zeroes on the right to come out to places digits after the decimal place.

Examples:

9324089.56.commas #=> '9,324,089.56'
88883.14159.commas #=>'88,883.1416'
88883.14159.commas(2) #=>'88,883.14'

Parameters:

  • places (Integer) (defaults to: nil)

    number of decimal place to round to

Returns:



38
39
40
# File 'lib/fat_core/numeric.rb', line 38

def commas(places = nil)
  group(places, ',')
end

#group(places = nil, delim = ',') ⇒ String

Convert this number into a string and insert grouping delimiter character, delim into the whole number part and round the decimal part to places decimal places, with the default number of places being zero for an integer and 4 for a non-integer. The fractional part is padded with zeroes on the right to come out to places digits after the decimal place. This is the same as #commas, but allows the delimiter to be any string.

Examples:

9324089.56.group          #=> '9,324,089.56'
9324089.56.group(4)       #=> '9,324,089.5600'
88883.14159.group         #=>'88,883.1416'
88883.14159.group(2)      #=>'88,883.14'
88883.14159.group(2, '_') #=>'88_883.14'

Parameters:

  • places (Integer) (defaults to: nil)

    number of decimal place to round to

  • delim (String) (defaults to: ',')

    use delim as group separator

Returns:



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
# File 'lib/fat_core/numeric.rb', line 59

def group(places = nil, delim = ',')
  # Return number as a string with embedded commas
  # for nice printing; round to places places after
  # the decimal

  # Only convert to string numbers with exponent unless they are
  # less than 1 (to ensure that really small numbers round to 0.0)
  return to_s if abs > 1.0 && to_s.include?('e')

  # Round if places given
  str =
    if places.nil?
      whole? ? to_i.to_s : to_f.to_s
    else
      to_f.round(places).to_s
    end

  # Break the number into parts; underscores are possible in all components.
  str =~ /\A(?<sg>[-+])?(?<wh>[\d_]*)((\.)?(?<fr>[\d_]*))?(?<ex>x[eE][+-]?[\d_]+)?\z/
  sig = Regexp.last_match[:sg] || ''
  whole = Regexp.last_match[:wh] ? Regexp.last_match[:wh].delete('_') : ''
  frac = Regexp.last_match[:fr] || ''
  exp = Regexp.last_match[:ex] || ''

  # Pad out the fractional part with zeroes to the right
  unless places.nil?
    n_zeroes = [places - frac.length, 0].max
    frac += '0' * n_zeroes if n_zeroes.positive?
  end

  # Place the commas in the whole part only
  whole = whole.reverse
  whole.gsub!(/([0-9]{3})/, "\\1#{delim}")
  whole.gsub!(/#{Regexp.escape(delim)}$/, '')
  whole.reverse!
  if frac.blank? # || places <= 0
    sig + whole + exp
  else
    sig + whole + '.' + frac + exp
  end
end

#int_if_wholeNumeric, Integer

Return an Integer type, but only if the fractional part of self is zero; otherwise just return self.

Examples:

45.98.int_if_whole #=> 45.98
45.000.int_if_whole #=> 45

Returns:



120
121
122
# File 'lib/fat_core/numeric.rb', line 120

def int_if_whole
  whole? ? floor : self
end

#secs_to_hmsString

Convert self, regarded as a number of seconds, into a string of the form HH:MM:SS.dd, that is to hours, minutes and seconds and fractions of seconds.

Examples:

5488.secs_to_hms #=> "01:31:28"

Returns:

  • (String)

    formatted as HH:MM:SS.dd



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/fat_core/numeric.rb', line 131

def secs_to_hms
  frac = self % 1
  mins, secs = divmod(60)
  hrs, mins = mins.divmod(60)
  if frac.round(5) > 0.0
    format(
      '%02<hrs>d:%02<mins>d:%02<secs>d.%<frac>d',
      {
        hrs: hrs,
        mins: mins,
        secs: secs,
        frac: frac.round(5) * 100
      },
    )
  else
    format(
      '%02<hrs>d:%02<mins>d:%02<secs>d',
      { hrs: hrs, mins: mins, secs: secs },
    )
  end
end

#signumInteger

Return the signum function for this number, i.e., 1 for a positive number, 0 for zero, and -1 for a negative number.

Examples:

-55.signum #=> -1
0.signum   #=> 0
55.signum  #=> 1

Returns:

  • (Integer)

    -1, 0, or 1 for negative, zero or positive self

Raises:

  • (NotImplementedError)


17
18
19
20
21
22
23
# File 'lib/fat_core/numeric.rb', line 17

def signum
  raise NotImplementedError unless real?
  return 1 if positive?
  return -1 if negative?

  0
end

#tex_quoteObject

Quote self for use in TeX documents. Since number components are not special to TeX, this just applies #to_s



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/fat_core/numeric.rb', line 155

def tex_quote
  case self
  when Float
    if self == Float::INFINITY
      "$\\infty$"
    elsif self == -Float::INFINITY
      "$-\\infty$"
    elsif self == Math::PI
      "$\\pi$"
    elsif self == Math::E
      "$e$"
    else
      to_s.tex_quote
    end
  when Rational
    "$\\frac{#{numerator}}{#{denominator}}$"
  when Complex
    if imaginary.zero?
      real.int_if_whole.tex_quote
    elsif imaginary == 1.0
      if real == Math::PI
        "$\\pi+i$"
      elsif real == Math::E
        "$e+i$"
      else
        "$#{real.int_if_whole}+i$"
      end
    elsif imaginary == Math::PI
      if real == Math::PI
        "$\\pi+\\pi i$"
      elsif real == Math::E
        "$e+\\pi i$"
      else
        "$#{real.int_if_whole}+\\pi i$"
      end
    elsif imaginary == Math::E
      if real == Math::PI
        "$\\pi+e i$"
      elsif real == Math::E
        "$e+e i$"
      else
        "$#{real.int_if_whole}+e i$"
      end
    else
      "$#{real.int_if_whole}+#{imaginary.int_if_whole}i$"
    end
  else
    to_s.tex_quote
  end
end

#whole?Boolean

Return whether this is a whole number.

Examples:

23.45.whole? #=> false
23.whole?    #=> true

Returns:

  • (Boolean)

    is self whole?



108
109
110
# File 'lib/fat_core/numeric.rb', line 108

def whole?
  floor == self
end