Class: Plusminus::PlusminusFloat

Inherits:
Numeric
  • Object
show all
Defined in:
lib/plusminus/plusminus_float.rb

Constant Summary collapse

DEFAULT_FMT =
Nio::Fmt.default.dup

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Numeric

#pm, #pm_rel

Constructor Details

#initialize(value, delta) ⇒ PlusminusFloat

Returns a new instance of PlusminusFloat.



5
6
7
8
# File 'lib/plusminus/plusminus_float.rb', line 5

def initialize value, delta
  @value = value.to_f
  @delta = delta.to_f.abs
end

Instance Attribute Details

#deltaObject (readonly)

Returns the value of attribute delta.



10
11
12
# File 'lib/plusminus/plusminus_float.rb', line 10

def delta
  @delta
end

#valueObject (readonly)

Returns the value of attribute value.



10
11
12
# File 'lib/plusminus/plusminus_float.rb', line 10

def value
  @value
end

Instance Method Details

#*(other) ⇒ Object



43
44
45
46
# File 'lib/plusminus/plusminus_float.rb', line 43

def * other
  other = other.to_pm
  (self.value * other.value).pm(other.value.abs * self.delta + self.value.abs * other.delta)
end

#**(other) ⇒ Object



53
54
55
56
57
58
59
60
61
62
# File 'lib/plusminus/plusminus_float.rb', line 53

def ** other
  return 1 if other == 0
  return 0 if self == 0
  other = other.to_pm
  res = self.value ** other.value
  res.pm(
    (Math.log(self.value.abs) * res).abs * other.delta +
    (other.value * res / self.value).abs * self.delta
  )
end

#+(other) ⇒ Object



33
34
35
36
# File 'lib/plusminus/plusminus_float.rb', line 33

def + other
  other = other.to_pm
  (@value + other.value).pm(@delta + other.delta)
end

#-(other) ⇒ Object



38
39
40
41
# File 'lib/plusminus/plusminus_float.rb', line 38

def - other
  other = other.to_pm
  (@value - other.value).pm(@delta + other.delta)
end

#-@Object



64
65
66
# File 'lib/plusminus/plusminus_float.rb', line 64

def -@
  (-@value).pm @delta
end

#/(other) ⇒ Object



48
49
50
51
# File 'lib/plusminus/plusminus_float.rb', line 48

def / other
  other = other.to_pm
  (self.value / other.value).pm(self.delta / other.value.abs + other.delta * self.value.abs / other.value.abs**2)
end

#<=>(other) ⇒ Object



81
82
83
# File 'lib/plusminus/plusminus_float.rb', line 81

def <=> other
  self.value <=> other.to_pm.value
end

#==(other) ⇒ Object



72
73
74
# File 'lib/plusminus/plusminus_float.rb', line 72

def == other
  @value == other
end

#===(other) ⇒ Object



85
86
87
88
# File 'lib/plusminus/plusminus_float.rb', line 85

def === other
  other = other.to_pm.value
  @value-@delta < other and other < @value+@delta
end

#absObject



68
69
70
# File 'lib/plusminus/plusminus_float.rb', line 68

def abs
  @value.abs
end

#coerce(other) ⇒ Object



24
25
26
27
28
29
30
31
# File 'lib/plusminus/plusminus_float.rb', line 24

def coerce other
  case other
  when Numeric
    return other.to_pm, self
  else
    raise ArgumentError "#{other} cannot be coerced to #{self.class}"
  end
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


76
77
78
79
# File 'lib/plusminus/plusminus_float.rb', line 76

def eql? other
  return false unless other.is_a? self.class
  self.value == other.value and self.delta == other.delta
end

#fmtObject

returns the Nio::Fmt to be used with the number. The returned object can be modified with Nio::Fmt’s bang methods



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/plusminus/plusminus_float.rb', line 92

def fmt
  unless defined? @fmt
    @fmt = DEFAULT_FMT.dup
    case @value
    when -0.01 ... 0.01 then 
      @fmt.mode!(:sci, sig_digits)
    else 
      @fmt.mode!(:sig, sig_digits)
    end
  end

  @fmt
end

#hashObject



20
21
22
# File 'lib/plusminus/plusminus_float.rb', line 20

def hash
  @value.hash
end

#inspectObject



132
133
134
# File 'lib/plusminus/plusminus_float.rb', line 132

def inspect
  "#{@value.inspect}.pm(#{delta.inspect})"
end

#nio_write(fmt = nil) ⇒ Object

produces a string of the number with the appropriate number of decimal digits



124
125
126
# File 'lib/plusminus/plusminus_float.rb', line 124

def nio_write fmt=nil
  @value.nio_write(fmt || self.fmt)
end

#sig_digitsObject

returns the number of significant digits



116
117
118
119
120
# File 'lib/plusminus/plusminus_float.rb', line 116

def sig_digits 
  return 0 if @value == 0
  return Float::DIG if @delta == 0
  Math.log(@value.abs,10).floor + 1.9999 - Math.log(@delta*2,10)
end

#to_fObject



16
17
18
# File 'lib/plusminus/plusminus_float.rb', line 16

def to_f
  @value
end

#to_latex(fmt = nil) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/plusminus/plusminus_float.rb', line 136

def to_latex fmt = nil
  fmt ||= self.fmt
  s = @value.nio_write(fmt || self.fmt)
  percent = s =~ /%\z/
  s.sub!(/%\z/, "")
  mantissa, exponent = s.split(/e/i)

  # if exponential form
  if exponent
    # strip decimal point or comma from end
    mantissa.sub!(/[^0-9a-zA-Z]+\z/, "") 

    exponent.sub!(/\A-0*/, "-").sub!(/\A0*/, "")
    res = "\\ensuremath{#{mantissa}\\cdot 10^{#{exponent}}}"
  else
    res = mantissa
  end

  res << "\\%" if percent
  res.respond_to?(:latex!) ? res.latex! : res
end

#to_latex_math_pmObject



163
164
165
166
# File 'lib/plusminus/plusminus_float.rb', line 163

def to_latex_math_pm
  res = "$#{to_latex_pm}$"
  res.respond_to?(:latex!) ? res.latex! : res
end

#to_latex_pmObject



158
159
160
161
# File 'lib/plusminus/plusminus_float.rb', line 158

def to_latex_pm
  res = "#{to_latex} \\pm #{@delta.pm_rel(0.1).to_latex}"
  res.respond_to?(:latex!) ? res.latex! : res
end

#to_pmObject



12
13
14
# File 'lib/plusminus/plusminus_float.rb', line 12

def to_pm
  self
end

#to_sObject



128
129
130
# File 'lib/plusminus/plusminus_float.rb', line 128

def to_s
  @value.to_s
end