numru-units 1.7.0
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.
- data/ChangeLog +111 -0
- data/LICENSE.txt +34 -0
- data/Makefile +14 -0
- data/Rakefile +39 -0
- data/doc/Makefile +5 -0
- data/doc/units.html +241 -0
- data/doc/units.rd +232 -0
- data/install.rb +104 -0
- data/lib/numru/units.rb +3505 -0
- data/src/Makefile +35 -0
- data/src/dcunits.txt +212 -0
- data/src/lex.rb +434 -0
- data/src/makeutab.rb +87 -0
- data/src/mulnode.rb +150 -0
- data/src/namenode.rb +63 -0
- data/src/node.rb +210 -0
- data/src/numbernode.rb +53 -0
- data/src/pownode.rb +98 -0
- data/src/rules.rb +65 -0
- data/src/shiftnode.rb +63 -0
- data/src/test.rb +122 -0
- data/src/timenode.rb +136 -0
- data/src/units.racc +2728 -0
- data/src/units.rb +3505 -0
- data/src/units.rd +139 -0
- data/src/utab.rb +1456 -0
- metadata +96 -0
data/src/Makefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
all: units.rb
|
2
|
+
|
3
|
+
units.rb: units.racc
|
4
|
+
racc -E -l units.racc -o tmp.rb
|
5
|
+
(ruby -n -e 'if /^class Units/; print("module NumRu\n",$$_); elsif /end\s*#\s*class\s*Units/; print($$_,"end # module NumRu\n"); else print $$_; end' tmp.rb > units.rb)
|
6
|
+
(( echo ; echo '####################' ; echo 'if $$0 == __FILE__' ; tail -n +2 test.rb | ruby -p -e 'print " "' ; echo 'end' ) >> units.rb)
|
7
|
+
@rm tmp.rb
|
8
|
+
|
9
|
+
test: units.rb
|
10
|
+
ruby test.rb
|
11
|
+
|
12
|
+
backup: units.shar
|
13
|
+
scp units.shar toyoda@www.gfd-dennou.org:tmp/
|
14
|
+
scp units.shar toyoda@pandora0.sytes.net:tmp/
|
15
|
+
|
16
|
+
RSRCS = rules.rb node.rb namenode.rb utab.rb numbernode.rb timenode.rb \
|
17
|
+
pownode.rb mulnode.rb shiftnode.rb lex.rb
|
18
|
+
|
19
|
+
utab.rb: makeutab.rb dcunits.txt
|
20
|
+
ruby makeutab.rb dcunits.txt > $@.tmp
|
21
|
+
mv $@.tmp $@
|
22
|
+
|
23
|
+
units.racc: $(RSRCS)
|
24
|
+
cat $(RSRCS) > $@.tmp
|
25
|
+
mv $@.tmp $@
|
26
|
+
|
27
|
+
edit:
|
28
|
+
$${EDITOR:-vi} $(RSRCS)
|
29
|
+
|
30
|
+
SRCS = Makefile units.rb dcunits.txt makeutab.rb $(RSRCS) test.rb units.rd
|
31
|
+
|
32
|
+
shar: units.shar
|
33
|
+
|
34
|
+
units.shar: $(SRCS)
|
35
|
+
shar $(SRCS) > units.shar
|
data/src/dcunits.txt
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
s S
|
2
|
+
second P s
|
3
|
+
m S
|
4
|
+
metre P m
|
5
|
+
meter P metre
|
6
|
+
kg S
|
7
|
+
kilogram P kg
|
8
|
+
A S
|
9
|
+
ampere P A
|
10
|
+
K S
|
11
|
+
kelvin P K
|
12
|
+
degK P K
|
13
|
+
deg_K P K
|
14
|
+
degreeK P K
|
15
|
+
mol S
|
16
|
+
mole P mol
|
17
|
+
rad S
|
18
|
+
radian P rad
|
19
|
+
sr S
|
20
|
+
steradian P sr
|
21
|
+
#
|
22
|
+
# --- standard named units ---
|
23
|
+
#
|
24
|
+
Hz S 1/s
|
25
|
+
hertz P Hz
|
26
|
+
N S kg.m.s-2
|
27
|
+
newton P N
|
28
|
+
Pa S N.m-2
|
29
|
+
pascal P Pa
|
30
|
+
Pascal P Pa
|
31
|
+
J S N.m
|
32
|
+
joule P J
|
33
|
+
W S J/s
|
34
|
+
watt P W
|
35
|
+
C S A.s
|
36
|
+
coulomb P C
|
37
|
+
V S J/C
|
38
|
+
volt P V
|
39
|
+
F S C/V
|
40
|
+
ohm S V/A
|
41
|
+
S S A/V
|
42
|
+
Wb S V.s
|
43
|
+
weber P Wb
|
44
|
+
farad P coulomb/volt
|
45
|
+
T S Wb.m-2
|
46
|
+
tesla P Wb.m-2
|
47
|
+
H S Wb.A-1
|
48
|
+
degC S K @ 273.15
|
49
|
+
deg_C S K @ 273.15
|
50
|
+
degree_C S K @ 273.15
|
51
|
+
degree_c S K @ 273.15
|
52
|
+
degreeC S K @ 273.15
|
53
|
+
Celsius P K @ 273.15
|
54
|
+
celsius P K @ 273.15
|
55
|
+
centigrade P K @ 273.15
|
56
|
+
degree_R S K / 1.8
|
57
|
+
degree_f S degree_R @ 459.67
|
58
|
+
degree_F S degree_R @ 459.67
|
59
|
+
Fahrenheit P degree_F
|
60
|
+
fahrenheit P degree_F
|
61
|
+
degF S degree_F
|
62
|
+
deg_F S degree_F
|
63
|
+
degreeF S degree_F
|
64
|
+
lm S cd.sr
|
65
|
+
lx S lm.m-2
|
66
|
+
Bq S s-1
|
67
|
+
Gy S J.kg-1
|
68
|
+
Sv S J.kg-1
|
69
|
+
#
|
70
|
+
# === non-SI units ===
|
71
|
+
#
|
72
|
+
# --- basic numbers ---
|
73
|
+
#
|
74
|
+
pi N 3.141592653589793238462
|
75
|
+
#
|
76
|
+
# --- nondimensional units ---
|
77
|
+
#
|
78
|
+
percent S 1e-2
|
79
|
+
% S 1e-2
|
80
|
+
permil S 1e-3
|
81
|
+
#
|
82
|
+
# --- length ---
|
83
|
+
#
|
84
|
+
fermi P 1.0e-15 m
|
85
|
+
angstrom P 1.0e-10 m
|
86
|
+
micron P 1.0e-6 m
|
87
|
+
astronomical_unit N 1.49597870e11 m
|
88
|
+
astronomical_units N 1.49597870e11 m
|
89
|
+
Au S astronomical_unit
|
90
|
+
parsec P 3.0857e16 m
|
91
|
+
pc S parsec
|
92
|
+
light_year N 9.46e15 m
|
93
|
+
light_years N 9.46e15 m
|
94
|
+
ly S light_year
|
95
|
+
nautical_mile N 1852 m
|
96
|
+
nautical_miles N 1852 m
|
97
|
+
#
|
98
|
+
inch P 2.54 cm
|
99
|
+
in S inch
|
100
|
+
foot N 12 inch
|
101
|
+
feet N foot
|
102
|
+
ft N foot
|
103
|
+
yard P 6 feet
|
104
|
+
yd P yard
|
105
|
+
chain P 22 yard
|
106
|
+
mile P 1760 yard
|
107
|
+
#
|
108
|
+
# --- time ---
|
109
|
+
#
|
110
|
+
minute P 60 s
|
111
|
+
min S 60 s
|
112
|
+
hour P 60 min
|
113
|
+
hr S 60 min
|
114
|
+
h S 60 min
|
115
|
+
day P 24 hour
|
116
|
+
d S 24 hour
|
117
|
+
Julian_year P 365.25 day
|
118
|
+
common_year P 365 day
|
119
|
+
#
|
120
|
+
# --- date ---
|
121
|
+
#
|
122
|
+
# date is NOT time intentionally
|
123
|
+
#
|
124
|
+
pentad P
|
125
|
+
month P 6 pentad
|
126
|
+
mon S month
|
127
|
+
year P 12 month
|
128
|
+
yr S year
|
129
|
+
century P 100 year
|
130
|
+
#
|
131
|
+
# --- area ---
|
132
|
+
#
|
133
|
+
are P 100 m2
|
134
|
+
a S are
|
135
|
+
hectare P 100 are
|
136
|
+
litre P 1.0e-3 m3
|
137
|
+
L S litre
|
138
|
+
acre P 10 chain2
|
139
|
+
ac S acre
|
140
|
+
#
|
141
|
+
# --- angle ---
|
142
|
+
#
|
143
|
+
degree P pi.rad/180
|
144
|
+
angular_degree P degree
|
145
|
+
minute_angle P pi.rad/180/60
|
146
|
+
angular_minute P minute_angle
|
147
|
+
second_angle P pi.rad/180/60/60
|
148
|
+
angular_second P second_angle
|
149
|
+
degree_N S degree
|
150
|
+
degree_E S degree
|
151
|
+
degree_W S degree
|
152
|
+
degree_S S degree
|
153
|
+
degree_north S degree_N
|
154
|
+
degree_east S degree_E
|
155
|
+
degree_west S degree_W
|
156
|
+
degree_south S degree_S
|
157
|
+
degrees_north S degree_N
|
158
|
+
degrees_east S degree_E
|
159
|
+
degrees_west S degree_W
|
160
|
+
degrees_south S degree_S
|
161
|
+
#
|
162
|
+
# --- mass ---
|
163
|
+
#
|
164
|
+
ton P 1000 kg
|
165
|
+
tonne P ton
|
166
|
+
t S ton
|
167
|
+
gram P kg/1000
|
168
|
+
g S kg/1000
|
169
|
+
pound P 453.6 g
|
170
|
+
lb S pound
|
171
|
+
ounce P pound / 16
|
172
|
+
oz S ounce
|
173
|
+
#
|
174
|
+
# --- CGS ---
|
175
|
+
#
|
176
|
+
dyne P g.cm.s-2
|
177
|
+
dyn S g.cm.s-2
|
178
|
+
bar S 1e6 dyn.cm-2
|
179
|
+
mb S bar / 1000
|
180
|
+
millibar P bar / 1000
|
181
|
+
gal P cm s-2
|
182
|
+
Gal S cm s-2
|
183
|
+
mgal S cm s-2 / 1000
|
184
|
+
erg S dyn cm
|
185
|
+
erg P dyn cm
|
186
|
+
poise P dyn s / cm2
|
187
|
+
P S poise
|
188
|
+
stokes P cm2 / s
|
189
|
+
St S stokes
|
190
|
+
gauss P T / 10000
|
191
|
+
G S gauss
|
192
|
+
#
|
193
|
+
# --- conventional ---
|
194
|
+
#
|
195
|
+
calorie P 4.18605 J
|
196
|
+
cal S calorie
|
197
|
+
kgf S kilogram-force
|
198
|
+
force S 9.80665 m.s-2
|
199
|
+
knot P nautical_mile / hour
|
200
|
+
horse_power N 75 m kilogram-force / s
|
201
|
+
atmosphere P 101325 Pa
|
202
|
+
atm S atmosphere
|
203
|
+
light_speed N 299792458 m/s
|
204
|
+
mph S mile / hour
|
205
|
+
kph S km / hour
|
206
|
+
torr P 133.322 Pa
|
207
|
+
psi S pound-force / inch2
|
208
|
+
gravity S 9.806650 meter/second2
|
209
|
+
conventional_mercury S gravity 13595.10 kg/m3
|
210
|
+
mercury S conventional_mercury
|
211
|
+
Hg S mercury
|
212
|
+
hg S mercury
|
data/src/lex.rb
ADDED
@@ -0,0 +1,434 @@
|
|
1
|
+
def initialize string
|
2
|
+
case string
|
3
|
+
when String
|
4
|
+
@string, @ptree = string, nil
|
5
|
+
when Node
|
6
|
+
@string, @ptree = nil, string
|
7
|
+
else
|
8
|
+
@string, @ptree = String(string), nil
|
9
|
+
end
|
10
|
+
@copy = @lexstat = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# === LEXICAL ANALYZER ===
|
15
|
+
#
|
16
|
+
|
17
|
+
def rewind
|
18
|
+
@copy = @string.dup.strip
|
19
|
+
@lexstat = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
RE_SPACE = '([ \t])'
|
23
|
+
RE_INTEGER = '([-+]?\d+)'
|
24
|
+
RE_EXP = '([eE][-+]?[0-9]+)'
|
25
|
+
RE_REAL = "([-+]?[0-9]*(\\.[0-9]*#{RE_EXP}?|#{RE_EXP}))"
|
26
|
+
RE_YEAR = "([-+]?[0-9]{1,4})"
|
27
|
+
RE_MONTH = "(0?[1-9]|1[0-2])"
|
28
|
+
RE_DAY = "([12][0-9]|30|31|0?[1-9])"
|
29
|
+
RE_HOUR = "(2[0-3]|[0-1]?[0-9])"
|
30
|
+
RE_MINUTE = "([0-5]?[0-9])"
|
31
|
+
RE_SECOND = "((#{RE_MINUTE}|60)(\\.[0-9]*)?)"
|
32
|
+
RE_NAME = "(%|[a-zA-Z][a-zA-Z_]*([0-9]+[a-zA-Z_]+)*)"
|
33
|
+
|
34
|
+
RE_DATE = "#{RE_YEAR}-#{RE_MONTH}-#{RE_DAY}"
|
35
|
+
RE_TIME = "#{RE_HOUR}((:[0-5]?[0-9]|[0-5][0-9])(:#{RE_SECOND})?)?"
|
36
|
+
RE_HandM = "#{RE_HOUR}((:[0-5]?[0-9]|[0-5][0-9]))?"
|
37
|
+
|
38
|
+
def next_token
|
39
|
+
|
40
|
+
# decomment
|
41
|
+
@copy.sub!(/^#.*/, '');
|
42
|
+
|
43
|
+
if @copy.sub!(%r{^\s*(\))}, '') then
|
44
|
+
@lexstat = nil
|
45
|
+
return [$1, $1]
|
46
|
+
end
|
47
|
+
|
48
|
+
if @copy.sub!(%r{^\s*(\()\s*}, '') then
|
49
|
+
return [$1, $1]
|
50
|
+
end
|
51
|
+
|
52
|
+
if @copy.sub!(%r{^[ \t]*(@)[ \t]*}, '') \
|
53
|
+
or @copy.sub!(%r{^[ \t]+(after|from|since|ref)[ \t]+}i, '') then
|
54
|
+
@lexstat = :SHIFT_SEEN
|
55
|
+
return [:SHIFT, $1]
|
56
|
+
end
|
57
|
+
|
58
|
+
if @copy.sub!(%r{^[ \t]*(/)[ \t]*}, '') \
|
59
|
+
or @copy.sub!(%r{^[ \t]+(per)[ \t]+}i, '') then
|
60
|
+
@lexstat = nil
|
61
|
+
return [:DIVIDE, $1]
|
62
|
+
end
|
63
|
+
|
64
|
+
if @copy.sub!(%r{^(\^|\*\*)}, '') then
|
65
|
+
@lexstat = nil
|
66
|
+
return [:EXPONENT, $1]
|
67
|
+
end
|
68
|
+
|
69
|
+
if @copy.sub!(%r{^(\.|\*|[ \t]+)}, '') then
|
70
|
+
@lexstat = nil
|
71
|
+
return [:MULTIPLY, $1]
|
72
|
+
end
|
73
|
+
|
74
|
+
if :SHIFT_SEEN === @lexstat \
|
75
|
+
and @copy.sub!(%r{^#{RE_DATE}T?[ \t]*}, '') then
|
76
|
+
y, m, d = $1, $2, $3
|
77
|
+
@lexstat = :DATE_SEEN
|
78
|
+
return [:DATE, XDate.new(y.to_i, m.to_i, d.to_i)]
|
79
|
+
end
|
80
|
+
|
81
|
+
if :SHIFT_SEEN === @lexstat \
|
82
|
+
and @copy.sub!(%r{^now[ \t]*}, '') then
|
83
|
+
@lexstat = nil
|
84
|
+
return [:DATE, :now]
|
85
|
+
end
|
86
|
+
|
87
|
+
if :DATE_SEEN === @lexstat \
|
88
|
+
and @copy.sub!(%r{^#{RE_TIME}[ \t]*}, '') then
|
89
|
+
h, m, s = $1, $3, $5
|
90
|
+
m = m.sub(/:/,'') if m
|
91
|
+
s = 0 if s.nil?
|
92
|
+
@lexstat = :TIME_SEEN
|
93
|
+
return [:TIME, ((h.to_i * 60 + m.to_i) * 60 + Float(s))]
|
94
|
+
end
|
95
|
+
|
96
|
+
if :DATE_SEEN === @lexstat \
|
97
|
+
and @copy.sub!(%r{^([0-2][0-9])([0-5][0-9])[ \t]*}, '') then
|
98
|
+
h, m = $1, $2
|
99
|
+
@lexstat = :TIME_SEEN
|
100
|
+
return [:TIME, ((h.to_i * 60 + m.to_i) * 60.0)]
|
101
|
+
end
|
102
|
+
|
103
|
+
if :DATE_SEEN === @lexstat \
|
104
|
+
and @copy.sub!(%r{^([0-9])([0-5][0-9])[ \t]*}, '') then
|
105
|
+
h, m = $1, $2
|
106
|
+
@lexstat = :TIME_SEEN
|
107
|
+
return [:TIME, ((h.to_i * 60 + m.to_i) * 60.0)]
|
108
|
+
end
|
109
|
+
|
110
|
+
if :TIME_SEEN === @lexstat \
|
111
|
+
and @copy.sub!(%r{^UTC[ \t]*}, '') then
|
112
|
+
@lexstat = nil
|
113
|
+
return [:ZONE, 0]
|
114
|
+
end
|
115
|
+
|
116
|
+
if :TIME_SEEN === @lexstat \
|
117
|
+
and @copy.sub!(%r{^([-+]?)#{RE_HandM}[ \t]*}, '') then
|
118
|
+
sgn, h, m = $1, $2, $4
|
119
|
+
m = m.sub(/:/,'') if m
|
120
|
+
@lexstat = nil
|
121
|
+
h = h.to_i
|
122
|
+
h = -h if sgn == "-"
|
123
|
+
m = m.to_i
|
124
|
+
m = -m if sgn == "-"
|
125
|
+
return [:ZONE, ((h * 60) + m)]
|
126
|
+
end
|
127
|
+
|
128
|
+
if @copy.sub!(%r{^#{RE_NAME}}, '') then
|
129
|
+
@lexstat = nil
|
130
|
+
return [:NAME, $1]
|
131
|
+
end
|
132
|
+
|
133
|
+
if @copy.sub!(%r{^#{RE_REAL}}, '') then
|
134
|
+
@lexstat = nil
|
135
|
+
return [:REAL, $1.to_f]
|
136
|
+
end
|
137
|
+
|
138
|
+
if @copy.sub!(%r{^#{RE_INTEGER}}, '') then
|
139
|
+
@lexstat = nil
|
140
|
+
return [:INT, $1.to_i]
|
141
|
+
end
|
142
|
+
|
143
|
+
if @copy.sub!(%r{^(-)}, '') then
|
144
|
+
@lexstat = nil
|
145
|
+
return [:MULTIPLY, $1]
|
146
|
+
end
|
147
|
+
|
148
|
+
if @copy.sub!(%r{^(.)}, '') then
|
149
|
+
return [$1, $1]
|
150
|
+
end
|
151
|
+
|
152
|
+
return [false, false]
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# === USER LEVEL METHODS ===
|
158
|
+
#
|
159
|
+
|
160
|
+
def tokens
|
161
|
+
rewind
|
162
|
+
x = []
|
163
|
+
while (t = next_token).first
|
164
|
+
x.push t
|
165
|
+
end
|
166
|
+
x
|
167
|
+
end
|
168
|
+
|
169
|
+
def do_parse2
|
170
|
+
rewind
|
171
|
+
return NumberNode.new(1) if @string.nil? or @string.empty?
|
172
|
+
pa = do_parse
|
173
|
+
pa ? pa : ErrorNode.new(@string)
|
174
|
+
end
|
175
|
+
|
176
|
+
def ptree
|
177
|
+
@ptree = do_parse2 if not @ptree
|
178
|
+
@ptree
|
179
|
+
end
|
180
|
+
|
181
|
+
def dup
|
182
|
+
@string ? self.class.new(@string) : self.class.new(@ptree)
|
183
|
+
end
|
184
|
+
|
185
|
+
def parse
|
186
|
+
dup.parse!
|
187
|
+
end
|
188
|
+
|
189
|
+
def parse!
|
190
|
+
@ptree = do_parse2 if not @ptree
|
191
|
+
self
|
192
|
+
end
|
193
|
+
|
194
|
+
def self::parse(string)
|
195
|
+
new(string).parse!
|
196
|
+
end
|
197
|
+
|
198
|
+
=begin
|
199
|
+
--- reduce0
|
200
|
+
just do nothing.
|
201
|
+
=end
|
202
|
+
|
203
|
+
def reduce0
|
204
|
+
self
|
205
|
+
end
|
206
|
+
|
207
|
+
=begin
|
208
|
+
--- reduce1
|
209
|
+
removes unnecessary parentheses.
|
210
|
+
=end
|
211
|
+
|
212
|
+
def reduce1
|
213
|
+
@string = ptree.to_s
|
214
|
+
self
|
215
|
+
end
|
216
|
+
|
217
|
+
=begin
|
218
|
+
--- reduce2
|
219
|
+
removes shift operator within multiplication/division/exponent
|
220
|
+
=end
|
221
|
+
|
222
|
+
def reduce2
|
223
|
+
@ptree = ptree.reduce2
|
224
|
+
@string = nil
|
225
|
+
self
|
226
|
+
end
|
227
|
+
|
228
|
+
=begin
|
229
|
+
--- reduce3
|
230
|
+
flattens expression and collects all factors
|
231
|
+
=end
|
232
|
+
|
233
|
+
def reduce3
|
234
|
+
@ptree = ptree.reduce3
|
235
|
+
@string = nil
|
236
|
+
self
|
237
|
+
end
|
238
|
+
|
239
|
+
=begin
|
240
|
+
--- reduce4
|
241
|
+
collects terms with the same name
|
242
|
+
=end
|
243
|
+
|
244
|
+
def reduce4
|
245
|
+
@ptree = ptree.reduce4
|
246
|
+
@string = nil
|
247
|
+
self
|
248
|
+
end
|
249
|
+
|
250
|
+
=begin
|
251
|
+
--- reduce5
|
252
|
+
expands all terms recursively
|
253
|
+
=end
|
254
|
+
|
255
|
+
def reduce5
|
256
|
+
@ptree = ptree.reduce5
|
257
|
+
@string = nil
|
258
|
+
self
|
259
|
+
end
|
260
|
+
|
261
|
+
attr_reader :string
|
262
|
+
|
263
|
+
def to_s
|
264
|
+
@string = @ptree.to_s if @string.nil?
|
265
|
+
@string
|
266
|
+
end
|
267
|
+
|
268
|
+
def inspect
|
269
|
+
if @ptree.nil? then
|
270
|
+
"Units{#{@string}}"
|
271
|
+
else
|
272
|
+
"Units[#{@ptree.inspect}]".gsub(/Units::/, '').gsub(/Node\[/, '[')
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def self::[](string)
|
277
|
+
new(string)
|
278
|
+
end
|
279
|
+
|
280
|
+
def self::parse(string)
|
281
|
+
new(string).parse!
|
282
|
+
end
|
283
|
+
|
284
|
+
def eval(x = 0)
|
285
|
+
r5 = ptree.reduce5
|
286
|
+
case r = r5.ref
|
287
|
+
when TimeNode
|
288
|
+
r.add(x, r5.name)
|
289
|
+
else
|
290
|
+
fac = NumberNode.new(x + r.value)
|
291
|
+
self.class.new(MulNode.new(fac, r5.deref))
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def convert(numeric, to_units)
|
296
|
+
to_units = Units.new( to_units ) if to_units.is_a?(String)
|
297
|
+
r5 = dup.ptree.reduce5
|
298
|
+
case r = r5.ref
|
299
|
+
when TimeNode
|
300
|
+
r.add_time(r5.deref.mul(numeric)).div_time(to_units.ptree)
|
301
|
+
else
|
302
|
+
shift1 = r.value
|
303
|
+
numeric = shift1 + numeric if shift1 != 0
|
304
|
+
fact = r5.divide(tp = to_units.dup.ptree).reduce5.value
|
305
|
+
numeric *= fact if fact != 1
|
306
|
+
shift2 = tp.reduce5.ref.value
|
307
|
+
numeric = numeric - shift2 if shift2 != 0
|
308
|
+
numeric
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def factor_and_offset(to_units)
|
313
|
+
# To convert a numeric from self to to_units:
|
314
|
+
# scale_factor * numeric + add_offset
|
315
|
+
to_units = Units.new( to_units ) if to_units.is_a?(String)
|
316
|
+
add_offset = convert(0, to_units)
|
317
|
+
scale_factor = convert(1, to_units) - add_offset
|
318
|
+
[ scale_factor, add_offset ]
|
319
|
+
end
|
320
|
+
|
321
|
+
def convert2(val, to_units)
|
322
|
+
# Like Units#convert, but applicable to any Numeric-like objects.
|
323
|
+
# Returns the original value if the units are incompatible.
|
324
|
+
to_units = Units.new( to_units ) if to_units.is_a?(String)
|
325
|
+
if ( self == to_units )
|
326
|
+
val
|
327
|
+
elsif ( self =~ to_units )
|
328
|
+
if Numeric===val
|
329
|
+
convert( val, to_units )
|
330
|
+
else
|
331
|
+
factor, offset = factor_and_offset( to_units )
|
332
|
+
val*factor + offset
|
333
|
+
end
|
334
|
+
else
|
335
|
+
unless $VERBOSE.nil?
|
336
|
+
$stderr.print( "*WARNING*: " +
|
337
|
+
"incompatible units: #{self.to_s} and #{to_units.to_s}\n")
|
338
|
+
caller(0).each{|c| $stderr.print "\t* ",c,"\n"}
|
339
|
+
end
|
340
|
+
val
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
@@reduce = :reduce4
|
345
|
+
|
346
|
+
def self::reduce_level
|
347
|
+
@@reduce.to_s[-1]
|
348
|
+
end
|
349
|
+
|
350
|
+
def self::reduce_level=(n)
|
351
|
+
@@reduce = case n
|
352
|
+
when 1 then :reduce1
|
353
|
+
when 2 then :reduce2
|
354
|
+
when 3 then :reduce3
|
355
|
+
when 4 then :reduce4
|
356
|
+
else :reduce5
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
def binop(op, other)
|
361
|
+
case other
|
362
|
+
when Numeric
|
363
|
+
other = NumberNode.new(other)
|
364
|
+
when Units
|
365
|
+
other = other.ptree
|
366
|
+
end
|
367
|
+
q = self.ptree.send(op, other).send(@@reduce)
|
368
|
+
Units.new(q)
|
369
|
+
end
|
370
|
+
|
371
|
+
def *(other)
|
372
|
+
binop(:mul, other)
|
373
|
+
end
|
374
|
+
|
375
|
+
def **(other)
|
376
|
+
binop(:pow, other)
|
377
|
+
end
|
378
|
+
|
379
|
+
def /(other)
|
380
|
+
binop(:divide, other)
|
381
|
+
end
|
382
|
+
|
383
|
+
def ^(other)
|
384
|
+
binop(:shift, other)
|
385
|
+
end
|
386
|
+
|
387
|
+
def ==(other)
|
388
|
+
case other
|
389
|
+
when self.class
|
390
|
+
dup.reduce5.to_s == other.dup.reduce5.to_s
|
391
|
+
else
|
392
|
+
false
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
#def === (other)
|
397
|
+
# reduce5.ptree.deref.to_s == other.reduce5.ptree.deref.to_s
|
398
|
+
#end
|
399
|
+
|
400
|
+
alias === ==
|
401
|
+
|
402
|
+
#def === (other)
|
403
|
+
# # returns true if other is within a factor and/or offset of difference.
|
404
|
+
# case other
|
405
|
+
# when self.class
|
406
|
+
# (self/other).reduce5.ptree.children.each do |child|
|
407
|
+
# return false if !( NumberNode === child )
|
408
|
+
# end
|
409
|
+
# true
|
410
|
+
# else
|
411
|
+
# false
|
412
|
+
# end
|
413
|
+
#end
|
414
|
+
|
415
|
+
|
416
|
+
def =~(other)
|
417
|
+
case other
|
418
|
+
when self.class
|
419
|
+
(self/other).reduce5.ptree.children.each{ |node|
|
420
|
+
return false unless NumberNode === node
|
421
|
+
}
|
422
|
+
true
|
423
|
+
else
|
424
|
+
false
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
def self::pow_f(a, b)
|
429
|
+
if Integer === b and b < 0 then
|
430
|
+
a ** b.to_f
|
431
|
+
else
|
432
|
+
a ** b
|
433
|
+
end
|
434
|
+
end
|