numrepr 1.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.
- checksums.yaml +7 -0
- data/LICENSE +52 -0
- data/README.md +212 -0
- data/lib/numrepr/decimal.rb +296 -0
- data/lib/numrepr/format.rb +301 -0
- data/lib/numrepr/money.rb +337 -0
- data/lib/numrepr/percent.rb +236 -0
- data/lib/numrepr/version.rb +10 -0
- data/lib/numrepr.rb +9 -0
- data/numrepr.gemspec +36 -0
- metadata +54 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f1a48451e0600ba32b7e705a6182e152b79c65eb2e2cd5b8f5972d78dd7dfd1f
|
|
4
|
+
data.tar.gz: afe9490a19dc479341ccf3fa367c5496eac1cedc6cec8236db39b6645cd2cfe6
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 68523527b522f8ea6beb3a29ff580b7cb27c19f7cf64ca3424a48b108f4ee1e1a5b8c1ec7360d702481f6dcadfbcfa3cb4699fd11cec6f704a428b4c530e0ba3
|
|
7
|
+
data.tar.gz: f59b0cfe695b372b506696816239bfd9b420b5d99ba849d7ec4dac340d8ef172e15b79a8b3b4fbf4dc80cb682c039b0d4d9fdc84cede39d7bc3205e143d6ab97
|
data/LICENSE
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# BSD-2-clause license, extended by language use conditions
|
|
2
|
+
|
|
3
|
+
Copyright (C) 2026 Bertram Scharpf <software@bertram-scharpf.de>.
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are
|
|
8
|
+
met:
|
|
9
|
+
|
|
10
|
+
* Redistributions of source code must retain the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer.
|
|
12
|
+
|
|
13
|
+
* Redistributions in binary form must reproduce the above copyright
|
|
14
|
+
notice, this list of conditions and the following disclaimer in
|
|
15
|
+
the documentation and/or other materials provided with the
|
|
16
|
+
distribution.
|
|
17
|
+
|
|
18
|
+
* Redistributions must not contain any clauses about anticipated
|
|
19
|
+
harassment or discrimination, nor must they be held in a so-called
|
|
20
|
+
"inclusive language". As far as German language is used, the
|
|
21
|
+
conditions mentioned below additionally apply.
|
|
22
|
+
|
|
23
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
24
|
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
25
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
26
|
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
|
27
|
+
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
28
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
29
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
30
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
31
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
32
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
33
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## Use of the German Language
|
|
37
|
+
|
|
38
|
+
Beim Gebrauch deutscher Sprache sind Weiterentwicklungen und
|
|
39
|
+
-verbreitungen nur gestattet unter Einhaltung sowie abermaligen
|
|
40
|
+
Einforderns folgender zusätzlicher Bedingungen:
|
|
41
|
+
|
|
42
|
+
* Keine Verwendung von sogenannter „geschlechtergerechter Sprache“,
|
|
43
|
+
also Anfügen von weiblichen Endungen mit Binnen-I, Sternchen,
|
|
44
|
+
Doppelpunkt, Unterstrich oder ähnlichem, oder Konstruktionen, die
|
|
45
|
+
den Sachverhalt falsch wiedergeben („Radfahrende“, „Studierende“).
|
|
46
|
+
|
|
47
|
+
* Keine Verwendung der „reformierten Rechtschreibung“ von 1996,
|
|
48
|
+
insbesondere Doppel-S am Silbenende, „plazieren“ mit T, sowie
|
|
49
|
+
Großschreibung von Wendungen wie „des weiteren“.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
<!-- vim:set ft=markdown : -->
|
data/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Ruby-NumRepr
|
|
2
|
+
|
|
3
|
+
Number representations: Conversion from and to strings for Integer, Float, and
|
|
4
|
+
BigDecimal classes.
|
|
5
|
+
|
|
6
|
+
Classes for monetary und percent values.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```shell
|
|
13
|
+
sudo gem install numrepr
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Parsing and formatting integers:
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
require "numrepr/format"
|
|
23
|
+
|
|
24
|
+
i = NumRepr::Parser.into_i "12.345"
|
|
25
|
+
"#{NumRepr::Format.from_i i}" #=> "12345"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Custom format:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
require "numrepr/format"
|
|
32
|
+
|
|
33
|
+
class MyFmt < NumRepr::Format
|
|
34
|
+
NUMDIGITS = 0 # leave empty if zero
|
|
35
|
+
GRP = true
|
|
36
|
+
WIDTH = 8
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
[ 12345, -12345, 0].map { |i| "#{MyFmt.from_i i}" }
|
|
40
|
+
#=> [" 12,345", " -12,345", " "]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The standard parser recognizes comma as decimal separator as well
|
|
44
|
+
as the dot. You may define a custom parser that demands either.
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
require "numrepr/format"
|
|
48
|
+
|
|
49
|
+
%w(12,345 12.345).map { |s| NumRepr::Parser.into_i s }
|
|
50
|
+
#=> [12345, 12345]
|
|
51
|
+
|
|
52
|
+
class ParseDot < NumRepr::Parser
|
|
53
|
+
GRP = "."
|
|
54
|
+
end
|
|
55
|
+
class ParseComma < NumRepr::Parser
|
|
56
|
+
GRP = ","
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
%w(12,345 12.345).map { |s| ParseDot.into_i s rescue nil }
|
|
60
|
+
#=> [nil, 12345]
|
|
61
|
+
%w(12,345 12.345).map { |s| ParseComma.into_i s rescue nil }
|
|
62
|
+
#=> [12345, nil]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Parsing and formatting floats respectively decimals:
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
require "numrepr/format"
|
|
69
|
+
require "bigdecimal/util"
|
|
70
|
+
|
|
71
|
+
class FormatCustom < NumRepr::Format
|
|
72
|
+
# Change these and see what happens:
|
|
73
|
+
NUMDIGITS = 10
|
|
74
|
+
POS = false
|
|
75
|
+
GRP = true
|
|
76
|
+
WIDTH = 16
|
|
77
|
+
DEC = true # force decimal point
|
|
78
|
+
NUMPLACES = 0
|
|
79
|
+
RWIDTH = 8
|
|
80
|
+
ZSIGN = true
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
nums = %w(
|
|
84
|
+
1.0 0.0 -0.0
|
|
85
|
+
0.1 0.1234 0.00456 0.000456 0.0000456
|
|
86
|
+
123456789.0 1230000.0
|
|
87
|
+
-1234.56789
|
|
88
|
+
NaN Infinity -Infinity
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
nums.each { |s|
|
|
92
|
+
puts "|#{FormatCustom::from_d s.to_d}|"
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Result:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
| 0,000,000,001. |
|
|
100
|
+
| 0,000,000,000. |
|
|
101
|
+
| -0,000,000,000. |
|
|
102
|
+
| 0,000,000,000.1 |
|
|
103
|
+
| 0,000,000,000.123,4 |
|
|
104
|
+
| 0,000,000,000.004,56 |
|
|
105
|
+
| 0,000,000,000.000,456 |
|
|
106
|
+
| 0,000,000,000.000,045,6|
|
|
107
|
+
| 0,123,456,789. |
|
|
108
|
+
| 0,001,230,000. |
|
|
109
|
+
| -0,000,001,234.567,89 |
|
|
110
|
+
| NaN |
|
|
111
|
+
| Inf |
|
|
112
|
+
| -Inf |
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Parsing:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
require "numrepr/format"
|
|
119
|
+
require "bigdecimal/util"
|
|
120
|
+
|
|
121
|
+
%w(12,345.678,999 12.345,678.999).map { |s| NumRepr::Parser.into_d s }
|
|
122
|
+
#=> [12345.678999, 12345.678999]
|
|
123
|
+
|
|
124
|
+
class ParseDot < NumRepr::Parser
|
|
125
|
+
GRP = "."
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
%w(12,345.678,999 12.345,678.999).map { |s| ParseDot.into_d s rescue nil }
|
|
129
|
+
#=> [nil, 12345.678999]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
### Monetary values
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
require "numrepr/money"
|
|
137
|
+
include NumRepr
|
|
138
|
+
|
|
139
|
+
class FormatEU < Format
|
|
140
|
+
CHDEC = ","
|
|
141
|
+
GRP = true
|
|
142
|
+
CHGRP = "."
|
|
143
|
+
DASH = true
|
|
144
|
+
CURSYM = "€"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
amount = Parser.into_money "€ 12,345.-"
|
|
148
|
+
puts amount
|
|
149
|
+
puts "|#{FormatEU::from_money amount}|"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Result:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
$12345.00
|
|
156
|
+
|€12.345,- |
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Default parsing:
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
require "numrepr/money"
|
|
163
|
+
include NumRepr
|
|
164
|
+
|
|
165
|
+
Parser.into_money "€ 12,345.-" #=> $12345.00
|
|
166
|
+
Parser.into_money "€ 12.345,-" #=> $12345.00
|
|
167
|
+
Parser.into_money "12.345,-€" #=> $12345.00
|
|
168
|
+
Parser.into_money "EUR 12.345,-" #=> $12345.00
|
|
169
|
+
Parser.into_money "12.345,-EUR" #=> $12345.00
|
|
170
|
+
Parser.into_money "12.345,67 EUR" #=> $12345.67
|
|
171
|
+
Parser.into_money "12.345,67€" #=> $12345.67
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
### Percent values
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
require "numrepr/money"
|
|
179
|
+
require "numrepr/percent"
|
|
180
|
+
include NumRepr
|
|
181
|
+
|
|
182
|
+
vat = "19%".to_percent
|
|
183
|
+
n = "100.00".to_money
|
|
184
|
+
|
|
185
|
+
n * vat #=> $19.00
|
|
186
|
+
vat.over n #=> $119.00
|
|
187
|
+
vat.split n #=> [$84.03, $15.97]
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
If an amount cannot be split into a base and a percent increase,
|
|
191
|
+
it can be forced to the next lower number.
|
|
192
|
+
|
|
193
|
+
```ruby
|
|
194
|
+
require "numrepr/money"
|
|
195
|
+
require "numrepr/percent"
|
|
196
|
+
include NumRepr
|
|
197
|
+
|
|
198
|
+
vat = "19%".to_percent
|
|
199
|
+
b = "69.99".to_money
|
|
200
|
+
vat.split b #=> raises NoSolutionError
|
|
201
|
+
n, t = vat.split! b #=> [$58.82, $11.17]
|
|
202
|
+
c = vat.over n #=> $70.00
|
|
203
|
+
vat.split c #=> [$58.82, $11.18]
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
## Copyright
|
|
208
|
+
|
|
209
|
+
* (C) 2026 Bertram Scharpf <software@bertram-scharpf.de>.
|
|
210
|
+
* License: [BSD-2-Clause+](./LICENSE)
|
|
211
|
+
* Repository: [ruby-numrepr](https://github.com/BertramScharpf/ruby-numrepr)
|
|
212
|
+
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
#
|
|
2
|
+
# decimal.rb -- Umlimited precision decimal
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
# This is just a study. Please use the standard +BigDecimal+.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
require "numrepr/format"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
module NumRepr
|
|
12
|
+
|
|
13
|
+
class Decimal
|
|
14
|
+
|
|
15
|
+
BASE = 10
|
|
16
|
+
|
|
17
|
+
@precision = 16
|
|
18
|
+
|
|
19
|
+
class <<self
|
|
20
|
+
|
|
21
|
+
attr_accessor :precision
|
|
22
|
+
|
|
23
|
+
alias parse new
|
|
24
|
+
|
|
25
|
+
def zero ; new nil ; end
|
|
26
|
+
|
|
27
|
+
def as obj
|
|
28
|
+
case obj
|
|
29
|
+
when self then obj
|
|
30
|
+
else new obj
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
attr_reader :mant, :expo
|
|
37
|
+
|
|
38
|
+
def initialize mant, expo = nil
|
|
39
|
+
@mant, @expo =
|
|
40
|
+
case mant
|
|
41
|
+
when Integer then [ mant, 0]
|
|
42
|
+
when Rational then parse_num mant.to_f
|
|
43
|
+
when Numeric then parse_num mant
|
|
44
|
+
else parse_str mant.to_s
|
|
45
|
+
end
|
|
46
|
+
@expo += expo.to_i if expo
|
|
47
|
+
norm!
|
|
48
|
+
rescue ArgumentError
|
|
49
|
+
raise ArgumentError, "Not a Decimal value: \"#{mant}\"."
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def mag ; BASE ** @expo ; end
|
|
53
|
+
alias magnitude mag
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def parse_num num
|
|
58
|
+
if num.respond_to? :split then # Will there ever be something like this for Float?
|
|
59
|
+
_, dig, _, exp = num.split
|
|
60
|
+
[ dig.to_i, exp - dig.length]
|
|
61
|
+
else
|
|
62
|
+
parse_str num.to_s
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def parse_str str
|
|
67
|
+
m, e = str.split /e/i, 2
|
|
68
|
+
e = e ? (Integer e, BASE) : 0
|
|
69
|
+
m.sub! %r/\./ do
|
|
70
|
+
e -= $'.count "0-9"
|
|
71
|
+
nil
|
|
72
|
+
end
|
|
73
|
+
[ (Integer m, BASE), e]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
public
|
|
77
|
+
|
|
78
|
+
def eql? oth ; self.class == oth.class and @mant == oth.mant and @expo == oth.expo ; end
|
|
79
|
+
|
|
80
|
+
def hash ; [@mant,@expo].hash ; end
|
|
81
|
+
|
|
82
|
+
def to_decimal ; self ; end
|
|
83
|
+
|
|
84
|
+
def to_f ; @mant.to_f * mag ; end
|
|
85
|
+
def to_i ; Integer @mant * mag ; end
|
|
86
|
+
def to_r ; Rational @mant * mag ; end
|
|
87
|
+
def to_d ; @mant.to_d * mag ; end
|
|
88
|
+
|
|
89
|
+
def succ! ; add! 1 ; end
|
|
90
|
+
def pred! ; sub! 1 ; end
|
|
91
|
+
def succ ; dup.succ! ; end
|
|
92
|
+
def pred ; dup.pred! ; end
|
|
93
|
+
|
|
94
|
+
def zero? ; @mant.zero? ; end
|
|
95
|
+
def nonzero? ; @mant.nonzero? and self ; end
|
|
96
|
+
|
|
97
|
+
def sign ; @mant ; end
|
|
98
|
+
def positive? ; @mant.positive? ; end
|
|
99
|
+
def negative? ; @mant.negative? ; end
|
|
100
|
+
alias pos? positive?
|
|
101
|
+
alias neg? negative?
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
def norm!
|
|
106
|
+
if @mant.zero? then
|
|
107
|
+
@expo = 0
|
|
108
|
+
else
|
|
109
|
+
loop do
|
|
110
|
+
m, r = @mant.divmod BASE
|
|
111
|
+
break if r.nonzero?
|
|
112
|
+
@mant = m
|
|
113
|
+
@expo += 1
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
self
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def same_expo oth
|
|
120
|
+
oth = Decimal.new oth unless Decimal === oth
|
|
121
|
+
om, oe = oth.mant, oth.expo
|
|
122
|
+
while @expo > oe do
|
|
123
|
+
@mant *= BASE
|
|
124
|
+
@expo -= 1
|
|
125
|
+
end
|
|
126
|
+
while @expo < oe do
|
|
127
|
+
om *= BASE
|
|
128
|
+
oe -= 1
|
|
129
|
+
end
|
|
130
|
+
om
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
public
|
|
134
|
+
|
|
135
|
+
def add! oth ; m = same_expo oth ; @mant += m ; norm! ; end
|
|
136
|
+
def sub! oth ; m = same_expo oth ; @mant -= m ; norm! ; end
|
|
137
|
+
def add oth ; dup.add! oth ; end
|
|
138
|
+
def sub oth ; dup.sub! oth ; end
|
|
139
|
+
|
|
140
|
+
def mul! oth
|
|
141
|
+
oth = Decimal.new oth unless Decimal === oth
|
|
142
|
+
@mant *= oth.mant
|
|
143
|
+
@expo += oth.expo
|
|
144
|
+
norm!
|
|
145
|
+
end
|
|
146
|
+
def mul oth ; dup.mul! oth ; end
|
|
147
|
+
|
|
148
|
+
def div! oth, precision = 0
|
|
149
|
+
oth = Decimal.new oth unless Decimal === oth
|
|
150
|
+
@expo -= oth.expo
|
|
151
|
+
neg = @mant.negative?
|
|
152
|
+
@mant, n = 0, @mant.abs
|
|
153
|
+
t = (precision||self.class.precision).to_i
|
|
154
|
+
while t + @expo >= 0 do
|
|
155
|
+
n, r = n.divmod oth.mant
|
|
156
|
+
@mant += n
|
|
157
|
+
break if r.zero?
|
|
158
|
+
n = r
|
|
159
|
+
n *= BASE
|
|
160
|
+
@mant *= BASE
|
|
161
|
+
@expo -= 1
|
|
162
|
+
end
|
|
163
|
+
@mant = -@mant if neg
|
|
164
|
+
norm!
|
|
165
|
+
end
|
|
166
|
+
def div oth, precision = 0 ; dup.div! oth, precision ; end
|
|
167
|
+
|
|
168
|
+
def quo! oth, precision = nil ; div! oth, precision ; end
|
|
169
|
+
def quo oth, precision = nil ; dup.quo! oth, precision ; end
|
|
170
|
+
|
|
171
|
+
alias + add
|
|
172
|
+
alias - sub
|
|
173
|
+
alias * mul
|
|
174
|
+
alias / div
|
|
175
|
+
|
|
176
|
+
def neg! ; @mant = -@mant ; self ; end
|
|
177
|
+
def neg ; dup.neg! ; end
|
|
178
|
+
def +@ ; self ; end
|
|
179
|
+
def -@ ; neg ; end
|
|
180
|
+
|
|
181
|
+
def abs ; self.class.new @mant.abs, @expo ; end
|
|
182
|
+
|
|
183
|
+
def <=> oth
|
|
184
|
+
case oth
|
|
185
|
+
when Decimal then (@expo <=> oth.expo).nonzero? || (@mant <=> oth.mant)
|
|
186
|
+
when Numeric then (@mant.to_f * 10 ** @expo) <=> oth
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
include Comparable
|
|
190
|
+
|
|
191
|
+
def coerce oth ; [ oth, to_r] ; end
|
|
192
|
+
|
|
193
|
+
def round! precision = nil, method = nil
|
|
194
|
+
s = -@expo - precision.to_i
|
|
195
|
+
if s <= 0 then
|
|
196
|
+
self
|
|
197
|
+
else
|
|
198
|
+
neg = @mant.negative?
|
|
199
|
+
g = BASE ** s
|
|
200
|
+
@mant, r = @mant.abs.divmod g
|
|
201
|
+
@expo += s
|
|
202
|
+
r *= 2
|
|
203
|
+
up =
|
|
204
|
+
case method||:comm
|
|
205
|
+
when :comm then r >= g
|
|
206
|
+
when :stat then r > g || r == g && @mant.odd?
|
|
207
|
+
when :trunc then false
|
|
208
|
+
when :ceil then true
|
|
209
|
+
when :up then !neg
|
|
210
|
+
when :down then neg
|
|
211
|
+
else raise ArgumentError, "Unknown rounding method: #{method}"
|
|
212
|
+
end
|
|
213
|
+
@mant += 1 if up
|
|
214
|
+
@mant = -@mant if neg
|
|
215
|
+
norm!
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
def round precision = nil, method = nil ; dup.round! precision, method ; end
|
|
219
|
+
|
|
220
|
+
def trunc! precision = nil ; round! precision, :trunc ; end
|
|
221
|
+
def trunc precision = nil ; dup.trunc! precision ; end
|
|
222
|
+
def ceil! precision = nil ; round! precision, :ceil ; end
|
|
223
|
+
def ceil precision = nil ; dup.ceil! precision ; end
|
|
224
|
+
|
|
225
|
+
def make_digits
|
|
226
|
+
d, f = "", ""
|
|
227
|
+
n = @mant.abs
|
|
228
|
+
e = @expo < 0 ? @expo : 0
|
|
229
|
+
in_d = false
|
|
230
|
+
loop do
|
|
231
|
+
if e >= 0 then
|
|
232
|
+
in_d = true
|
|
233
|
+
end
|
|
234
|
+
if e < @expo then
|
|
235
|
+
r = 0
|
|
236
|
+
else
|
|
237
|
+
break if n.zero? and in_d
|
|
238
|
+
n, r = n.divmod 10
|
|
239
|
+
end
|
|
240
|
+
e += 1
|
|
241
|
+
(in_d ? d : f) << (r + "0".ord).chr
|
|
242
|
+
end
|
|
243
|
+
f.reverse!
|
|
244
|
+
[ d, f]
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def raw
|
|
248
|
+
d, f = make_digits
|
|
249
|
+
d << "0" if d.empty?
|
|
250
|
+
d << "-" if negative?
|
|
251
|
+
d.reverse!
|
|
252
|
+
f.empty? or d << "." << f
|
|
253
|
+
d
|
|
254
|
+
end
|
|
255
|
+
alias to_s raw
|
|
256
|
+
def inspect
|
|
257
|
+
r = @mant.to_s
|
|
258
|
+
r << "e" << @expo.to_s unless @expo.zero?
|
|
259
|
+
r
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
class Parser
|
|
265
|
+
|
|
266
|
+
class <<self
|
|
267
|
+
|
|
268
|
+
def into_decimal str
|
|
269
|
+
digs = prepare_float str
|
|
270
|
+
Decimal digs
|
|
271
|
+
rescue ArgumentError, NoMethodError
|
|
272
|
+
raise ArgumentError, "Couldn't parse as a decimal: #{str}"
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
class Format
|
|
280
|
+
|
|
281
|
+
class <<self
|
|
282
|
+
alias from_decimal from_d
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def Decimal v ; Decimal.new v ; end
|
|
289
|
+
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class NilClass ; def to_decimal ; NumRepr::Decimal.new self ; end ; end
|
|
294
|
+
class Numeric ; def to_decimal ; NumRepr::Decimal.new self ; end ; end
|
|
295
|
+
class String ; def to_decimal ; NumRepr::Decimal.new self ; end ; end
|
|
296
|
+
|