numeric_with_unit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|