numeric_with_unit 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/numeric_with_unit.rb +193 -0
- data/lib/numeric_with_unit/base_unit.rb +179 -0
- data/lib/numeric_with_unit/cgs_unit.rb +19 -0
- data/lib/numeric_with_unit/common_unit.rb +112 -0
- data/lib/numeric_with_unit/imperial_unit.rb +43 -0
- data/lib/numeric_with_unit/natural_unit.rb +14 -0
- data/lib/numeric_with_unit/unit.rb +353 -0
- data/lib/numeric_with_unit/util.rb +27 -0
- data/lib/numeric_with_unit/util2.rb +66 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 48d05ab9f9aa01a815b412324ef7a04b198041db
|
4
|
+
data.tar.gz: 5b55204a0a0b340dfe941ea141e29f6977197a34
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d52e9021767bdbfee29dde88feaa8a64790475db07c0cee5df91c79f546e88604d08097f95a4730088df620336760d74d68f7f1f8ac9bf583f87ab7505b71a18
|
7
|
+
data.tar.gz: e3d277dee997ad68c2b38c8a4c06d6404b60bc1fb8d0328661055b5f75904afc834a8a6513d07c0d0e56688ae0577f6c35352c3fc1020080a92f8d8e0fea20ff
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'numeric_with_unit/unit'
|
4
|
+
|
5
|
+
class NumericWithUnit
|
6
|
+
include Comparable
|
7
|
+
|
8
|
+
attr_reader :value, :unit
|
9
|
+
|
10
|
+
def initialize(value, unit)
|
11
|
+
@value = value
|
12
|
+
@unit = unit.is_a?(Unit) ? unit : Unit[unit]
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
"#{@value.inspect} [#{@unit.symbol}] #{unit.dimension.inspect}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"#{@value.to_s} #{@unit.symbol}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# otherがNumericWithUnitで次元が同じだったらsi単位に変換して比較、そうでなければ比較できない(nil)
|
24
|
+
def <=>(other)
|
25
|
+
if other.is_a?(self.class) and @unit.dimension_equal? other.unit
|
26
|
+
@unit.to_si(@value) <=> other.unit.to_si(other.value)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def succ
|
31
|
+
self.class.new(@value.succ, @unit)
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_i
|
35
|
+
@value.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_f
|
39
|
+
@value.to_f
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_nwu(unit)
|
43
|
+
new_unit = unit.is_a?(Unit) ? unit : Unit[unit]
|
44
|
+
|
45
|
+
unless @unit.dimension_equal? new_unit
|
46
|
+
raise DimensionError, "Dimensions are different between #{@unit.symbol}#{@unit.dimension} #{new_unit.symbol}#{new_unit.dimension}"
|
47
|
+
end
|
48
|
+
|
49
|
+
new_value = new_unit.from_si(@unit.to_si(@value))
|
50
|
+
self.class.new(new_value, new_unit)
|
51
|
+
end
|
52
|
+
alias :[] :to_nwu
|
53
|
+
|
54
|
+
def +@
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def -@
|
59
|
+
self.class.new(-@value, @unit)
|
60
|
+
end
|
61
|
+
|
62
|
+
def +(other)
|
63
|
+
nwu = if other.is_a? self.class
|
64
|
+
other
|
65
|
+
else
|
66
|
+
self.class.new(other, Unit.new)
|
67
|
+
end
|
68
|
+
add_with_other_unit(nwu)
|
69
|
+
end
|
70
|
+
|
71
|
+
def -(other)
|
72
|
+
self + (-other)
|
73
|
+
end
|
74
|
+
|
75
|
+
def *(other)
|
76
|
+
case other
|
77
|
+
when self.class
|
78
|
+
multiply_with_other_unit(other)
|
79
|
+
else
|
80
|
+
self.class.new(@value*other, @unit)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def /(other)
|
85
|
+
case other
|
86
|
+
when self.class
|
87
|
+
devide_with_other_unit(other)
|
88
|
+
else
|
89
|
+
self.class.new(@value/other, @unit)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def coerce(other)
|
94
|
+
if other.is_a?(self.class)
|
95
|
+
[other, self]
|
96
|
+
else
|
97
|
+
[self.class.new(other, Unit.new), self]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def **(num)
|
102
|
+
# Dimension Check
|
103
|
+
@unit.derivation.each do |k,v|
|
104
|
+
res = v * num
|
105
|
+
raise DimensionError, "Dimension of #{k.symbol}(#{v}*#{num}) must be Integer" unless res.to_i == res # 判定方法見なおせ
|
106
|
+
end
|
107
|
+
|
108
|
+
self.class.new(@value**num, @unit**num)
|
109
|
+
end
|
110
|
+
|
111
|
+
def root(num)
|
112
|
+
self**(Rational(1,num))
|
113
|
+
end
|
114
|
+
def sqrt; root(2) end # 平方根
|
115
|
+
def cbrt; root(3) end # 立方根
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def add_with_other_unit(other)
|
120
|
+
if @unit.dimension_equal? other.unit
|
121
|
+
v1 = @unit.to_si(@value)
|
122
|
+
v2 = other.unit.to_si(other.value)
|
123
|
+
vr = @unit.from_si(v1+v2)
|
124
|
+
self.class.new(vr, @unit)
|
125
|
+
else
|
126
|
+
raise DimensionError, "Dimensions are different between #{@unit.dimension} #{other.unit.dimension}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def multiply_with_other_unit(other)
|
131
|
+
onwu = adjust_other_unit(other)
|
132
|
+
self.class.new(@value * onwu.value, @unit * onwu.unit)
|
133
|
+
end
|
134
|
+
|
135
|
+
def devide_with_other_unit(other)
|
136
|
+
onwu = adjust_other_unit(other)
|
137
|
+
self.class.new(@value / onwu.value, @unit / onwu.unit)
|
138
|
+
end
|
139
|
+
|
140
|
+
# なるべくselfと同じ単位を使用するようにotherを変換します。
|
141
|
+
def adjust_other_unit(other)
|
142
|
+
if @unit.derivation.any?{|k,v| k == other.unit} # [L/min]*[min]などのケース
|
143
|
+
other
|
144
|
+
elsif h = @unit.derivation.find{|k,v| k.dimension_equal? other.unit} # [L/min]*[s]などのケース
|
145
|
+
other[ h.first ]
|
146
|
+
elsif @unit.dimension_equal? other.unit # [mm]*[cm]などのケース
|
147
|
+
other[@unit]
|
148
|
+
else
|
149
|
+
other
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
|
157
|
+
class NumericWithUnit
|
158
|
+
class DimensionError < StandardError; end
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
|
163
|
+
class Fixnum
|
164
|
+
def to_nwu(unit)
|
165
|
+
NumericWithUnit.new(self, unit)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class Bignum
|
170
|
+
def to_nwu(unit)
|
171
|
+
NumericWithUnit.new(self, unit)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class Numeric
|
176
|
+
def to_nwu(unit)
|
177
|
+
NumericWithUnit.new(self, unit)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
class String
|
182
|
+
def to_nwu(mthd=:to_r)
|
183
|
+
m = self.match /(?<value>.+) (?<unit>.+)/ # 適当
|
184
|
+
NumericWithUnit[m[:value].__send__(mthd), m[:unit]]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
|
190
|
+
# unit definition
|
191
|
+
require 'numeric_with_unit/base_unit'
|
192
|
+
require 'numeric_with_unit/common_unit'
|
193
|
+
|
@@ -0,0 +1,179 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#
|
4
|
+
# SI base units & SI derived units & Units in use with SI
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'numeric_with_unit/unit'
|
8
|
+
|
9
|
+
class NumericWithUnit
|
10
|
+
# Dimensionless
|
11
|
+
Unit << Unit.new do |conf|
|
12
|
+
conf.symbol = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# SI base units
|
17
|
+
#
|
18
|
+
|
19
|
+
# Length
|
20
|
+
Unit << Unit.new do |conf|
|
21
|
+
conf.symbol = 'm'
|
22
|
+
conf.dimension[:L] = 1
|
23
|
+
conf.si = true
|
24
|
+
end
|
25
|
+
|
26
|
+
# Mass
|
27
|
+
Unit << Unit.new do |conf|
|
28
|
+
conf.symbol = 'kg'
|
29
|
+
conf.dimension[:M] = 1
|
30
|
+
conf.si = true
|
31
|
+
end
|
32
|
+
Unit['g'] = "1/1000".to_r, 'kg' # for compatible
|
33
|
+
|
34
|
+
# Time
|
35
|
+
Unit << Unit.new do |conf|
|
36
|
+
conf.symbol = 's'
|
37
|
+
conf.dimension[:T] = 1
|
38
|
+
conf.si = true
|
39
|
+
end
|
40
|
+
|
41
|
+
# Electric Current
|
42
|
+
Unit << Unit.new do |conf|
|
43
|
+
conf.symbol = 'A'
|
44
|
+
conf.dimension[:I] = 1
|
45
|
+
conf.si = true
|
46
|
+
end
|
47
|
+
|
48
|
+
# Thermodynamic Temperature
|
49
|
+
Unit << Unit.new do |conf|
|
50
|
+
conf.symbol = 'K'
|
51
|
+
conf.dimension[:Θ] = 1
|
52
|
+
conf.si = true
|
53
|
+
end
|
54
|
+
|
55
|
+
# Amout of Substance
|
56
|
+
Unit << Unit.new do |conf|
|
57
|
+
conf.symbol = 'mol'
|
58
|
+
conf.dimension[:N] = 1
|
59
|
+
conf.si = true
|
60
|
+
end
|
61
|
+
|
62
|
+
# Luminous Intensity
|
63
|
+
Unit << Unit.new do |conf|
|
64
|
+
conf.symbol = 'cd'
|
65
|
+
conf.dimension[:J] = 1
|
66
|
+
conf.si = true
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
#
|
72
|
+
# SI derived units
|
73
|
+
#
|
74
|
+
|
75
|
+
# Frequency
|
76
|
+
Unit['Hz'] = '/s'
|
77
|
+
|
78
|
+
# Angle
|
79
|
+
Unit['rad'] = 'm/m'
|
80
|
+
Unit['°'] = Math::PI/180, 'rad'
|
81
|
+
Unit['′'] = "1/60".to_r, '°'
|
82
|
+
Unit['″'] = "1/60".to_r, '′'
|
83
|
+
|
84
|
+
# Solid Angle
|
85
|
+
Unit['sr'] = 'm2/m2'
|
86
|
+
|
87
|
+
# Force
|
88
|
+
Unit['N'] = 'kg.m/s2'
|
89
|
+
|
90
|
+
# Pressure
|
91
|
+
Unit['Pa'] = 'N/m2'
|
92
|
+
|
93
|
+
# Energy
|
94
|
+
Unit['J'] = 'N.m'
|
95
|
+
|
96
|
+
# Power
|
97
|
+
Unit['W'] = 'J/s'
|
98
|
+
|
99
|
+
# Electric Charge
|
100
|
+
Unit['C'] = 's.A'
|
101
|
+
|
102
|
+
# Voltage
|
103
|
+
Unit['V'] = 'W/A'
|
104
|
+
|
105
|
+
# Electriccal Capacitance
|
106
|
+
Unit['F'] = 'C/V'
|
107
|
+
|
108
|
+
# Electriccal Resistance
|
109
|
+
Unit['Ω'] = 'V/A'
|
110
|
+
Unit['ohm'] = 'Ω'
|
111
|
+
|
112
|
+
# Electriccal Conductance
|
113
|
+
Unit['S'] = 'A/V'
|
114
|
+
|
115
|
+
# Magnetic Flux
|
116
|
+
Unit['Wb'] = 'J/A'
|
117
|
+
|
118
|
+
# Magnetic Field Strength
|
119
|
+
Unit['T'] = 'Wb/m2'
|
120
|
+
|
121
|
+
# Inductance
|
122
|
+
Unit['H'] = 'V.s/A'
|
123
|
+
|
124
|
+
# Temperature
|
125
|
+
Unit << Unit.new do |conf|
|
126
|
+
k = Unit['K']
|
127
|
+
intercept = "273.15".to_r
|
128
|
+
|
129
|
+
conf.symbol = '℃'
|
130
|
+
conf.dimension = k.dimension
|
131
|
+
conf.from_si{|x| k.from_si(x)-intercept}
|
132
|
+
conf.to_si{|x| k.to_si(x+intercept)}
|
133
|
+
end
|
134
|
+
Unit['degC'] = '℃'
|
135
|
+
|
136
|
+
# Luminouse flux
|
137
|
+
Unit['lx'] = 'cd.sr'
|
138
|
+
|
139
|
+
# Radioactivity
|
140
|
+
Unit['Bq'] = '/s'
|
141
|
+
|
142
|
+
# Absorbed Dose
|
143
|
+
Unit['Gy'] = 'J/kg'
|
144
|
+
|
145
|
+
# Equivalent Dose
|
146
|
+
Unit['Sv'] = 'J/kg'
|
147
|
+
|
148
|
+
# Catalytic Activity
|
149
|
+
Unit['kat'] = 'mol/s'
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
#
|
154
|
+
# Units in use with SI
|
155
|
+
#
|
156
|
+
|
157
|
+
# Time
|
158
|
+
Unit['min'] = 60, 's'
|
159
|
+
Unit['hr'] = 60, 'min'
|
160
|
+
|
161
|
+
# Area
|
162
|
+
Unit['a'] = 100, 'm2'
|
163
|
+
|
164
|
+
# Volume
|
165
|
+
Unit['L'] = 'dm3'
|
166
|
+
|
167
|
+
# Mass
|
168
|
+
Unit['t'] = 1000, 'kg'
|
169
|
+
|
170
|
+
# Energy
|
171
|
+
Unit['eV'] = "1.6021765314e-19".to_r, 'J'
|
172
|
+
|
173
|
+
# Mass
|
174
|
+
Unit['u'] = "1.6605388628e-27".to_r, 'kg'
|
175
|
+
Unit['Da'] = 'u'
|
176
|
+
|
177
|
+
# Length
|
178
|
+
Unit['ua'] = "1.495978706916e11".to_r, 'm'
|
179
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'numeric_with_unit/base_unit'
|
4
|
+
|
5
|
+
Unit['cal'] = "4.184".to_r, 'J'
|
6
|
+
|
7
|
+
Unit['Gal'] = 'cm/s2'
|
8
|
+
|
9
|
+
Unit['dyn'] = 'g.cm/s2'
|
10
|
+
|
11
|
+
Unit['erg'] = 'g.cm2/s2'
|
12
|
+
|
13
|
+
Unit['Ba'] = 'g/(cm.s2)'
|
14
|
+
|
15
|
+
Unit['P'] = 'g/(cm.s)'
|
16
|
+
Unit['poise'] = 'g/(cm.s)'
|
17
|
+
|
18
|
+
Unit['St'] = 'cm2/s'
|
19
|
+
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#
|
4
|
+
# 独断と偏見による一般的な単位
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'numeric_with_unit/unit'
|
8
|
+
require 'numeric_with_unit/base_unit'
|
9
|
+
|
10
|
+
class NumericWithUnit
|
11
|
+
# Dimensionless
|
12
|
+
Unit['-'] = ''
|
13
|
+
Unit['1'] = ''
|
14
|
+
|
15
|
+
# Time
|
16
|
+
Unit['day'] = 24, 'hr'
|
17
|
+
Unit['week'] = 7, 'day'
|
18
|
+
Unit['month'] = 30, 'day' # 30日固定
|
19
|
+
Unit['year'] = 12, 'month' # 360日固定
|
20
|
+
|
21
|
+
# Mass
|
22
|
+
Unit['ton'] = 1000, 'kg'
|
23
|
+
Unit['oz'] = "28.349523125".to_r, 'g'
|
24
|
+
Unit['lb'] = 16, 'oz'
|
25
|
+
|
26
|
+
# Temperature
|
27
|
+
Unit['degC'] = '℃'
|
28
|
+
Unit['degR'] = "5/9".to_r, 'K'
|
29
|
+
Unit << Unit.new do |conf|
|
30
|
+
degr = Unit['degR']
|
31
|
+
intercept = "459.67".to_r
|
32
|
+
|
33
|
+
conf.symbol = 'degF'
|
34
|
+
conf.dimension = degr.dimension
|
35
|
+
conf.from_si{|x| degr.from_si(x)-intercept}
|
36
|
+
conf.to_si{|x| degr.to_si(x+intercept)}
|
37
|
+
end
|
38
|
+
|
39
|
+
# Length
|
40
|
+
Unit['Å'] = 10**-10, 'm'
|
41
|
+
Unit['yd'] = "0.9144".to_r, 'm'
|
42
|
+
Unit['ft'] = "1/3".to_r, 'yd'
|
43
|
+
Unit['in'] = "1/12".to_r, 'ft'
|
44
|
+
Unit['mi'] = 5280, 'ft'
|
45
|
+
|
46
|
+
# Volume
|
47
|
+
Unit['cc'] = 'cm3'
|
48
|
+
Unit['bbl'] = "0.158987294928".to_r, 'm3'
|
49
|
+
|
50
|
+
# Force
|
51
|
+
Unit['kgf'] = "9.80665".to_r, 'N'
|
52
|
+
Unit['lbf'] = "4.4482216152605".to_r, 'N'
|
53
|
+
|
54
|
+
# Power
|
55
|
+
Unit['PS'] = 75, 'kgf.m/s' # 仏馬力。小文字[ps]だとpico secondと区別がつかないため大文字で定義
|
56
|
+
Unit['HP'] = 550, 'lbf.ft/s' # 英馬力
|
57
|
+
|
58
|
+
# Pressure
|
59
|
+
Unit['bar'] = 1e5, 'Pa'
|
60
|
+
Unit['atm'] = 101325, 'Pa'
|
61
|
+
Unit['Torr'] = "101325/760".to_r, 'Pa'
|
62
|
+
Unit['mmHg'] = "101325/760".to_r, 'Pa'
|
63
|
+
Unit['mHg'] = "1/1000".to_r, 'mmHg' # for compatible
|
64
|
+
Unit['mH2O'] = "9806.65".to_r, 'Pa'
|
65
|
+
Unit['mAq'] = 'mH2O'
|
66
|
+
Unit['psi'] = "6894.76".to_r, 'Pa'
|
67
|
+
|
68
|
+
# Guage圧の扱いどうしようか?
|
69
|
+
Unit << Unit.new do |conf|
|
70
|
+
pa = Unit['Pa']
|
71
|
+
atm = 101325
|
72
|
+
|
73
|
+
conf.symbol = 'PaG'
|
74
|
+
conf.dimension = pa.dimension
|
75
|
+
conf.from_si{|x| pa.from_si(x)-atm}
|
76
|
+
conf.to_si{|x| pa.to_si(x+atm)}
|
77
|
+
end
|
78
|
+
|
79
|
+
# Speed
|
80
|
+
Unit['kph'] = 'km/hr'
|
81
|
+
|
82
|
+
# Flowrate
|
83
|
+
Unit['lpm'] = 'L/min'
|
84
|
+
|
85
|
+
# Viscosity
|
86
|
+
Unit['P'] = "1/10".to_r, 'Pa.s'
|
87
|
+
|
88
|
+
# Kinetic Viscosity
|
89
|
+
Unit['St'] = 'cm2/s'
|
90
|
+
|
91
|
+
# Energy
|
92
|
+
Unit['cal'] = "4.184".to_r, 'J' # 熱力学カロリー
|
93
|
+
Unit['MMkcal'] = 10**6 * 10**3, 'cal'
|
94
|
+
Unit['Btu'] = "1055.05585262".to_r, 'J' # 国際蒸気表(IT)Btu
|
95
|
+
Unit['MMBtu'] = 10**6, 'Btu'
|
96
|
+
|
97
|
+
# Ratio
|
98
|
+
Unit['%'] = 10**-2, ''
|
99
|
+
Unit['‰'] = 10**-3, ''
|
100
|
+
Unit['ppm'] = 10**-6, ''
|
101
|
+
Unit['ppb'] = 10**-9, ''
|
102
|
+
|
103
|
+
|
104
|
+
# Infomation
|
105
|
+
Unit << Unit.new do |conf|
|
106
|
+
conf.symbol = 'bit'
|
107
|
+
# conf.dimension[:] = # 情報量の次元って何?
|
108
|
+
end
|
109
|
+
Unit['B'] = 8, 'bit'
|
110
|
+
Unit['bps'] = 'bit/s'
|
111
|
+
Unit['Bps'] = 'B/s'
|
112
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'numeric_with_unit/base_unit'
|
4
|
+
|
5
|
+
Unit['yd'] = "0.9144".to_r , 'm'
|
6
|
+
Unit['ft'] = "1/3".to_r, 'yd'
|
7
|
+
Unit['th'] = "1/12000".to_r, 'ft'
|
8
|
+
Unit['in'] = "1/12".to_r, 'ft'
|
9
|
+
Unit['ch'] = 66, 'ft'
|
10
|
+
Unit['fur'] = 660, 'ft'
|
11
|
+
Unit['mi'] = 5280, 'ft'
|
12
|
+
Unit['lea'] = 15840, 'ft'
|
13
|
+
|
14
|
+
|
15
|
+
Unit['floz'] = "2.84130625e-05".to_r, 'm3'
|
16
|
+
Unit['gi'] = 5, 'floz'
|
17
|
+
Unit['pt'] = 20, 'floz'
|
18
|
+
Unit['qt'] = 40, 'floz'
|
19
|
+
Unit['gal'] = 160, 'floz'
|
20
|
+
|
21
|
+
Unit['bbl'] = "0.158987294928".to_r, 'm3'
|
22
|
+
|
23
|
+
|
24
|
+
Unit['oz'] = "0.45359237".to_r, 'kg'
|
25
|
+
Unit['gr'] = "1/7000".to_r, 'oz'
|
26
|
+
Unit['dr'] = "1/256".to_r, 'oz'
|
27
|
+
Unit['lb'] = "1/16".to_r, 'oz'
|
28
|
+
Unit['st'] = 14, 'oz'
|
29
|
+
Unit['qtr'] = 28, 'oz'
|
30
|
+
Unit['cwt'] = 112, 'oz'
|
31
|
+
Unit['t'] = 2240, 'oz'
|
32
|
+
|
33
|
+
|
34
|
+
Unit['degR'] = "9/5".to_r, 'K'
|
35
|
+
|
36
|
+
Unit << Unit.new do |conf|
|
37
|
+
deg_r = Unit['degR']
|
38
|
+
conf.symbol = '℉'
|
39
|
+
conf.dimension = deg_r.dimension
|
40
|
+
conf.from_si = ->(x){(deg_r.from_si(x)) - 459.67}
|
41
|
+
conf.to_si = ->(x){deg_r.to_si(x + 459.67)}
|
42
|
+
end
|
43
|
+
Unit['degF'] = '℉'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'numeric_with_unit/base_unit'
|
4
|
+
|
5
|
+
# Naural Units
|
6
|
+
# Speed
|
7
|
+
Unit['c0'] = "299792458.0".to_r, 'm/s'
|
8
|
+
# Action
|
9
|
+
Unit['ħ'] = "1.0545716818e−34".to_r, 'J.s'
|
10
|
+
Unit['h'] = 'ħ' # alias
|
11
|
+
# Mass
|
12
|
+
Unit['me'] = "9.109382616e−31".to_r, 'kg'
|
13
|
+
# Time
|
14
|
+
Unit['ħ/(me.(c0)2)'] = "1.288088667786e-21".to_r, 's' # なんかきもい
|
@@ -0,0 +1,353 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
class NumericWithUnit
|
5
|
+
class Unit
|
6
|
+
class Config
|
7
|
+
attr_reader :symbol, :dimension, :derivation
|
8
|
+
attr_reader :si, :proportional
|
9
|
+
|
10
|
+
def initialize(parent=nil)
|
11
|
+
@symbol = nil
|
12
|
+
@dimension = Hash.new(0)
|
13
|
+
@from_si = nil
|
14
|
+
@to_si = nil
|
15
|
+
@derivation = Hash.new(0)
|
16
|
+
@si = false
|
17
|
+
|
18
|
+
@parent = parent
|
19
|
+
end
|
20
|
+
|
21
|
+
def compile
|
22
|
+
@dimension.delete_if{|k,v| v.zero?}
|
23
|
+
@derivation.delete_if{|k,v| v.zero?}
|
24
|
+
@derivation.delete_if{|k,v| k.symbol.nil?}
|
25
|
+
|
26
|
+
if @derivation.empty?
|
27
|
+
@from_si ||= ->(x){x}
|
28
|
+
@to_si ||= ->(x){x}
|
29
|
+
@derivation[@parent] += 1 unless @parent.nil?
|
30
|
+
else # configにderivationが与えられた時は、derivationをもとに@dimension,@symbol,@to_si,@from_siを設定
|
31
|
+
h = @derivation.sort_by{|u,v| u.symbol}.sort_by{|u,v| v} # ←どうしよう
|
32
|
+
|
33
|
+
s1 = h.select{|u,v| v > 0}.map{|u,v| u.symbol + ((v.abs>1) ? v.abs.to_s : '')}.join('.')
|
34
|
+
s2 = h.select{|u,v| v < 0}.map{|u,v| u.symbol + ((v.abs>1) ? v.abs.to_s : '')}.join('.')
|
35
|
+
@symbol = s1 + (s2.empty? ? '' : "/(#{s2})")
|
36
|
+
|
37
|
+
@derivation.each do |u,v|
|
38
|
+
u.dimension.each do |d,i|
|
39
|
+
@dimension[d] += i*v
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
@from_si = @derivation.map{|u,v|
|
44
|
+
prc = if v > 0
|
45
|
+
->(x){u.from_si(x)}
|
46
|
+
else
|
47
|
+
->(x){x.quo(u.from_si(1)-u.from_si(0))} # ℃とKの変換のような場合に、変換式の切片を消すため。変換式が線形じゃないケースは想定していない
|
48
|
+
end
|
49
|
+
[prc, v.abs]
|
50
|
+
}.map{|prc,v|
|
51
|
+
->(x){ v.times{x = prc[x]}; x }
|
52
|
+
}.reduce{|memo, prc|
|
53
|
+
->(x){memo[prc[x]]}
|
54
|
+
}
|
55
|
+
|
56
|
+
@to_si = @derivation.map{|u,v|
|
57
|
+
prc = if v > 0
|
58
|
+
->(x){u.to_si(x)}
|
59
|
+
else
|
60
|
+
->(x){x.quo(u.to_si(1)-u.to_si(0))} # ℃とKの変換のような場合に、変換式の切片を消すため。変換式が線形じゃないケースは想定していない
|
61
|
+
end
|
62
|
+
[prc, v.abs]
|
63
|
+
}.map{|prc,v|
|
64
|
+
->(x){ v.times{x = prc[x]}; x }
|
65
|
+
}.reduce{|memo, prc|
|
66
|
+
->(x){memo[prc[x]]}
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
def symbol=(arg)
|
74
|
+
@symbol = arg.to_s
|
75
|
+
end
|
76
|
+
|
77
|
+
def dimension=(arg)
|
78
|
+
raise unless arg.is_a?(Hash)
|
79
|
+
@dimension = arg
|
80
|
+
end
|
81
|
+
|
82
|
+
def from_si=(arg)
|
83
|
+
raise unless arg.is_a?(Proc)
|
84
|
+
@from_si = arg
|
85
|
+
end
|
86
|
+
|
87
|
+
def from_si(&block)
|
88
|
+
if block_given?
|
89
|
+
@from_si = block
|
90
|
+
else
|
91
|
+
@from_si
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_si=(arg)
|
96
|
+
raise unless arg.is_a?(Proc)
|
97
|
+
@to_si = arg
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_si(&block)
|
101
|
+
if block_given?
|
102
|
+
@to_si = block
|
103
|
+
else
|
104
|
+
@to_si
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def si=(arg)
|
109
|
+
raise unless [TrueClass, FalseClass].any?{|klass|arg.is_a?(klass)}
|
110
|
+
@si = arg
|
111
|
+
end
|
112
|
+
|
113
|
+
def derivation=(arg)
|
114
|
+
raise unless arg.is_a?(Hash)
|
115
|
+
@derivation = arg
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
class NumericWithUnit
|
124
|
+
class Unit
|
125
|
+
@@list = []
|
126
|
+
@@prefix = {
|
127
|
+
'Y' => 10**24,
|
128
|
+
'Z' => 10**21,
|
129
|
+
'E' => 10**18,
|
130
|
+
'P' => 10**15,
|
131
|
+
'T' => 10**12,
|
132
|
+
'G' => 10**9,
|
133
|
+
'M' => 10**6,
|
134
|
+
'k' => 10**3,
|
135
|
+
'h' => 10**2,
|
136
|
+
'da' => 10**1,
|
137
|
+
'd' => 10**-1,
|
138
|
+
'c' => 10**-2,
|
139
|
+
'm' => 10**-3,
|
140
|
+
'μ' => 10**-6,
|
141
|
+
'u' => 10**-6,
|
142
|
+
'n' => 10**-9,
|
143
|
+
'p' => 10**-12,
|
144
|
+
'f' => 10**-15,
|
145
|
+
'a' => 10**-18,
|
146
|
+
'z' => 10**-21,
|
147
|
+
'y' => 10**-24,
|
148
|
+
'Ki' => 2**10,
|
149
|
+
'Mi' => 2**20,
|
150
|
+
'Gi' => 2**30,
|
151
|
+
'Ti' => 2**40,
|
152
|
+
'Pi' => 2**50,
|
153
|
+
'Ei' => 2**60,
|
154
|
+
'Zi' => 2**70,
|
155
|
+
'Yi' => 2**80
|
156
|
+
}
|
157
|
+
|
158
|
+
# class methods
|
159
|
+
|
160
|
+
def self.[](arg)
|
161
|
+
self.parse(arg.to_s)
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.[]=(key, arg)
|
165
|
+
if arg.is_a?(Array) and arg.size == 2
|
166
|
+
a = [key, arg.first]
|
167
|
+
u = arg.last
|
168
|
+
else
|
169
|
+
a = [key]
|
170
|
+
u = arg
|
171
|
+
end
|
172
|
+
@@list << (u.is_a?(self) ? u : self[u]).cast(*a)
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.list
|
176
|
+
@@list.map(&:symbol)
|
177
|
+
end
|
178
|
+
|
179
|
+
def self.<<(arg)
|
180
|
+
if arg.is_a?(self)
|
181
|
+
@@list << arg
|
182
|
+
else
|
183
|
+
@@list << Unit[arg]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.delete(unit_symbol)
|
188
|
+
@@list.delete_if{|unit| unit.symbol == unit_symbol}
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.assign
|
192
|
+
@@list << self.new{|config| yield(config)}
|
193
|
+
end
|
194
|
+
|
195
|
+
def self.parse(unit_str)
|
196
|
+
a = parse_1st(unit_str)
|
197
|
+
parse_2nd([a])
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
# 文字列を配列にパース
|
202
|
+
# ex. 'J/(kg.K)' -> [#<Unit:J>, ['/', #<Unit:kg>, '.', #<Unit:K>]]
|
203
|
+
# とても手続き的な書き方で禿げる
|
204
|
+
def self.parse_1st(unit_str)
|
205
|
+
i = @@list.rindex{|u| u.symbol == unit_str}
|
206
|
+
return @@list[i] if i
|
207
|
+
|
208
|
+
return unit_str if unit_str =~ /^[\.\/]$/
|
209
|
+
|
210
|
+
# 再帰で呼び出す用
|
211
|
+
rec = ->(arg){__send__(__method__, arg)}
|
212
|
+
|
213
|
+
a = unit_str.scan(/(?<=\().*(?=\))|[\.\/]|[^\(\)\.\/]+/)
|
214
|
+
return a.map{|elem| rec[elem]} if a.size > 1
|
215
|
+
|
216
|
+
m = unit_str.match(/-?\d+$/)
|
217
|
+
return m.to_s if m and m.pre_match.empty?
|
218
|
+
return [rec[m.pre_match], m.to_s] if m
|
219
|
+
|
220
|
+
m = unit_str.match(/^(?<prefix>#{@@prefix.keys.join('|')})(?<unit>#{list.join('|')})$/)
|
221
|
+
return rec[m[:unit]].cast(unit_str, @@prefix[m[:prefix]]) if m
|
222
|
+
|
223
|
+
raise NoUnitError, "\"#{unit_str}\" is not assigned"
|
224
|
+
end
|
225
|
+
private_class_method :parse_1st
|
226
|
+
|
227
|
+
# 配列を組立単位に変換
|
228
|
+
# derivationにそのまま突っ込んだほうがすっきりする気がする
|
229
|
+
def self.parse_2nd(unit_array)
|
230
|
+
# 再帰で呼び出す用
|
231
|
+
rec = ->(arg){__send__(__method__, arg)}
|
232
|
+
|
233
|
+
buff_ary = []
|
234
|
+
buff_unit = ''
|
235
|
+
buff_sign = 1
|
236
|
+
|
237
|
+
unit_array.each do |elem|
|
238
|
+
case elem
|
239
|
+
when self
|
240
|
+
buff_ary << elem ** buff_sign
|
241
|
+
when '.'
|
242
|
+
buff_sign = 1
|
243
|
+
when '/'
|
244
|
+
buff_sign = -1
|
245
|
+
when Array
|
246
|
+
buff_ary << rec[elem] ** buff_sign
|
247
|
+
when /^-?\d+$/
|
248
|
+
buff_ary[-1] **= elem.to_i
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
buff_ary.reduce(:*)
|
253
|
+
end
|
254
|
+
private_class_method :parse_2nd
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
|
260
|
+
class Unit
|
261
|
+
|
262
|
+
# Instance Methods
|
263
|
+
|
264
|
+
# attr_accessor :symbol
|
265
|
+
attr_reader :symbol
|
266
|
+
attr_reader :dimension, :derivation
|
267
|
+
|
268
|
+
def initialize
|
269
|
+
|
270
|
+
# Unit::Configとinitializeの役割が分離できていないので見なおせ
|
271
|
+
config = Config.new(self)
|
272
|
+
yield(config) if block_given?
|
273
|
+
config.compile
|
274
|
+
|
275
|
+
@symbol = config.symbol
|
276
|
+
@dimension = config.dimension
|
277
|
+
@from_si = config.from_si
|
278
|
+
@to_si = config.to_si
|
279
|
+
|
280
|
+
@derivation = config.derivation
|
281
|
+
end
|
282
|
+
|
283
|
+
def cast(new_symbol, factor = 1)
|
284
|
+
self.class.new do |conf|
|
285
|
+
conf.symbol = new_symbol
|
286
|
+
conf.dimension = @dimension
|
287
|
+
conf.from_si = ->(x){from_si(x.quo(factor))}
|
288
|
+
conf.to_si = ->(x){to_si(x * factor)}
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def to_s
|
293
|
+
@symbol
|
294
|
+
end
|
295
|
+
|
296
|
+
def to_si(value)
|
297
|
+
@to_si[value]
|
298
|
+
end
|
299
|
+
|
300
|
+
def from_si(value)
|
301
|
+
@from_si[value]
|
302
|
+
end
|
303
|
+
|
304
|
+
|
305
|
+
def dimensionless?
|
306
|
+
@dimension.all?{|k,v| v.zero?}
|
307
|
+
end
|
308
|
+
|
309
|
+
def dimension_equal?(other_unit)
|
310
|
+
(@dimension.keys | other_unit.dimension.keys).all?{|k|
|
311
|
+
@dimension[k] == other_unit.dimension[k]
|
312
|
+
}
|
313
|
+
end
|
314
|
+
|
315
|
+
def ==(other)
|
316
|
+
if other.is_a?(self.class)
|
317
|
+
symbol == other.symbol and dimension == other.dimension
|
318
|
+
else
|
319
|
+
super
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def *(other_unit)
|
324
|
+
self.class.new do |conf|
|
325
|
+
@derivation.each{|k, v| conf.derivation[k] += v}
|
326
|
+
other_unit.derivation.each{|k, v| conf.derivation[k] += v}
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def /(other_unit)
|
331
|
+
self.class.new do |conf|
|
332
|
+
@derivation.each{|k, v| conf.derivation[k] += v}
|
333
|
+
other_unit.derivation.each{|k, v| conf.derivation[k] -= v}
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
def **(num)
|
338
|
+
if num.zero?
|
339
|
+
self.class.new
|
340
|
+
else
|
341
|
+
self.class.new do |conf|
|
342
|
+
# ここto_iでOKか?v*numが整数じゃなければraiseすべき?→すべき→NumericWithUnitでやるべき?
|
343
|
+
# Unitでは整数じゃない次数の単位は許容すべきか否か→していい気がする
|
344
|
+
@derivation.each{|k, v| conf.derivation[k] = (v*num).to_i}
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
class Unit
|
351
|
+
class NoUnitError < StandardError; end
|
352
|
+
end
|
353
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# 1234['m3/kg']のように書けるようにします。
|
4
|
+
# Numeric#[]、Fixnum#[]、Bignum#[]をオーバーライドします。
|
5
|
+
|
6
|
+
require 'numeric_with_unit'
|
7
|
+
|
8
|
+
class NumericWithUnit
|
9
|
+
module NumUtil
|
10
|
+
def [](unit)
|
11
|
+
NumericWithUnit.new(self.rationalize, unit) # ratoinalizeする?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Fixnum
|
17
|
+
prepend NumericWithUnit::NumUtil
|
18
|
+
end
|
19
|
+
|
20
|
+
class Bignum
|
21
|
+
prepend NumericWithUnit::NumUtil
|
22
|
+
end
|
23
|
+
|
24
|
+
class Numeric
|
25
|
+
prepend NumericWithUnit::NumUtil
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
# 123.m2.K_W のように書けるようにします。
|
4
|
+
# method_missing をオーバーライドします。
|
5
|
+
|
6
|
+
require 'numeric_with_unit'
|
7
|
+
|
8
|
+
class NumericWithUnit
|
9
|
+
def method_missing(*args)
|
10
|
+
if args.size == 1
|
11
|
+
unit_str = args.first.to_s.gsub('_', '/')
|
12
|
+
unit_chain_util(Unit[unit_str])
|
13
|
+
else
|
14
|
+
raise Unit::NoUnitError
|
15
|
+
end
|
16
|
+
rescue Unit::NoUnitError
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_writer :unit_chain
|
21
|
+
|
22
|
+
private
|
23
|
+
def unit_chain_util(unit)
|
24
|
+
ucs = @unit_chain || []
|
25
|
+
ucs.map!{|nwu, u| [nwu, u * unit]}
|
26
|
+
ucs << [self, unit]
|
27
|
+
|
28
|
+
if i = ucs.index{|nwu, u| nwu.unit.dimension_equal? u}
|
29
|
+
nwu, nu = *ucs[i]
|
30
|
+
nwu[nu]
|
31
|
+
else
|
32
|
+
nnwu = self.class.new(@value, @unit*unit)
|
33
|
+
nnwu.unit_chain = ucs
|
34
|
+
nnwu
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
class NumericWithUnit
|
41
|
+
module NumUtil
|
42
|
+
def method_missing(*args)
|
43
|
+
if args.size == 1
|
44
|
+
unit_str = args.first.to_s.gsub('_', '/')
|
45
|
+
self.rationalize.to_nwu(unit_str) # util2は利便性優先なのでratoinalizeしてしまいます
|
46
|
+
else
|
47
|
+
raise Unit::NoUnitError
|
48
|
+
end
|
49
|
+
rescue Unit::NoUnitError
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
class Fixnum
|
57
|
+
prepend NumericWithUnit::NumUtil
|
58
|
+
end
|
59
|
+
|
60
|
+
class Bignum
|
61
|
+
prepend NumericWithUnit::NumUtil
|
62
|
+
end
|
63
|
+
|
64
|
+
class Numeric
|
65
|
+
prepend NumericWithUnit::NumUtil
|
66
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: numeric_with_unit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- diaphragm
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-18 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: calclation numeric with unit!!!!
|
14
|
+
email:
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/numeric_with_unit.rb
|
20
|
+
- lib/numeric_with_unit/base_unit.rb
|
21
|
+
- lib/numeric_with_unit/cgs_unit.rb
|
22
|
+
- lib/numeric_with_unit/common_unit.rb
|
23
|
+
- lib/numeric_with_unit/imperial_unit.rb
|
24
|
+
- lib/numeric_with_unit/natural_unit.rb
|
25
|
+
- lib/numeric_with_unit/unit.rb
|
26
|
+
- lib/numeric_with_unit/util.rb
|
27
|
+
- lib/numeric_with_unit/util2.rb
|
28
|
+
homepage: https://github.com/diaphragm/ruby-numeric-with-unit
|
29
|
+
licenses:
|
30
|
+
- MIT
|
31
|
+
metadata: {}
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
require_paths:
|
35
|
+
- lib
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 2.2.2
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: calclation numeric with unit
|
52
|
+
test_files: []
|