flt 1.5.0 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +8 -0
  3. data/README.md +765 -0
  4. data/expand.rb +2 -0
  5. data/flt.gemspec +1 -0
  6. data/lib/flt.rb +1 -1
  7. data/lib/flt/bigdecimal.rb +2 -5
  8. data/lib/flt/bin_num.rb +1 -4
  9. data/lib/flt/complex.rb +10 -9
  10. data/lib/flt/dec_num.rb +9 -10
  11. data/lib/flt/float.rb +4 -6
  12. data/lib/flt/math.rb +3 -4
  13. data/lib/flt/num.rb +54 -21
  14. data/lib/flt/sugar.rb +1 -2
  15. data/lib/flt/support.rb +5 -2
  16. data/lib/flt/support/flag_values.rb +1 -1
  17. data/lib/flt/support/rationalizer.rb +3 -3
  18. data/lib/flt/support/rationalizer_extra.rb +6 -6
  19. data/lib/flt/support/reader.rb +1 -1
  20. data/lib/flt/tolerance.rb +2 -7
  21. data/lib/flt/trigonometry.rb +0 -2
  22. data/lib/flt/version.rb +1 -1
  23. data/setup.rb +1 -2
  24. data/test/generate_trig_data.rb +6 -6
  25. data/test/helper.rb +11 -5
  26. data/test/reader.rb +1 -1
  27. data/test/test_base_digits.rb +4 -2
  28. data/test/test_basic.rb +7 -7
  29. data/test/test_big_decimal.rb +21 -21
  30. data/test/test_bin.rb +1 -1
  31. data/test/test_bin_arithmetic.rb +1 -1
  32. data/test/test_binfloat_conversion.rb +1 -1
  33. data/test/test_coercion.rb +1 -1
  34. data/test/test_comparisons.rb +4 -4
  35. data/test/test_dectest.rb +2 -2
  36. data/test/test_define_conversions.rb +10 -10
  37. data/test/test_epsilon.rb +1 -1
  38. data/test/test_exact.rb +12 -11
  39. data/test/test_flags.rb +1 -1
  40. data/test/test_float.rb +23 -25
  41. data/test/test_format.rb +1 -1
  42. data/test/test_formatter.rb +6 -8
  43. data/test/test_hex_format.rb +2 -2
  44. data/test/test_multithreading.rb +1 -1
  45. data/test/test_normalized.rb +1 -1
  46. data/test/test_num_constructor.rb +6 -1
  47. data/test/test_odd_even.rb +1 -1
  48. data/test/test_rationalizer.rb +1 -1
  49. data/test/test_round.rb +36 -1
  50. data/test/test_sugar.rb +6 -6
  51. data/test/test_to_int.rb +4 -4
  52. data/test/test_to_rf.rb +126 -1
  53. data/test/test_tol.rb +1 -1
  54. data/test/test_trig.rb +1 -1
  55. data/test/test_ulp.rb +3 -3
  56. metadata +18 -4
  57. data/README.rdoc +0 -614
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 84bc5146381ff127868320f22bb421bc8d1ad16a
4
- data.tar.gz: 66f6fc689cb2297638127a1217fe4ee3e19b8aa7
3
+ metadata.gz: 4944139b67630d8b78c7f29d004a71b79003e757
4
+ data.tar.gz: '0290ba88b15d6b1b0d050fe62cbd4cdaeb4cc856'
5
5
  SHA512:
6
- metadata.gz: 10bc77b0f1ab349a36abcf4512aa9a16aecc886e4da95ec2c6edc180c1c00b74113f98d2673f1c2aaae3cf7856b1be8291be0e59f2e9082f541cceae8c5f2130
7
- data.tar.gz: 1279653a5e9471834c3f48819db261bcb5cbf4e749ded3cc0d039a3e4bb3572eb20323b90fb0058739630b6bf8cd6eb36a6132713960da8f7b6c2919fca79122
6
+ metadata.gz: c7c630691b5ca086da656641ca04a7ef3f163c16661bb2be6cd32785980c5facbf3fdf2779bce955f72e6352ad43d95435497b74428f0abe30eb745b6559e364
7
+ data.tar.gz: 071b9592aec3c4edc7994f922722c7cd81cfd96d06430569432df8de135500c459842eba8d98e20705120ed913aabe5f3ef69a02e56ac43c6320be90f68cfd71
@@ -1,3 +1,11 @@
1
+ == 1.5.1 2017-02-28
2
+
3
+ * Bugfix & optimizations
4
+ - Num#to_f, BinNum#to_f are more accurate now
5
+ - Optimized Num#digits using Ruby 2.4 Integer#digits
6
+ - Optimized number_of_digits using Ruby 2.1 Integer#bit_length
7
+ - round interface is compatible with Ruby 2.4 options
8
+
1
9
  == 1.5.0 2015-04-06
2
10
 
3
11
  * New feature
@@ -0,0 +1,765 @@
1
+ # Flt
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/flt.svg)](http://badge.fury.io/rb/flt)
4
+ [![Build Status](https://travis-ci.org/jgoizueta/flt.svg)](https://travis-ci.org/jgoizueta/flt)
5
+
6
+ This library provides arbitrary precision floating-point types for Ruby. All
7
+ types and functions are within a namespace called Flt. Decimal and Binary
8
+ floating point numbers are implemented in classes Flt::DecNum and Flt::BinNum.
9
+ These types are completely written in Ruby using the multiple precision native
10
+ integers. The performance could be improved in the future by using a C
11
+ extension based on the decNumber library.
12
+
13
+ The `Flt::Tolerance` classes and the `Flt.Tolerance()` constructor handle floating
14
+ point tolerances defined in flexible ways.
15
+
16
+ Context classes are defined in the files [flt/float.rb](lib/flt/float_rb.html)
17
+ and [flt/bigdecimal.rb](lib/flt/bigdecimal_rb.html) for Float and BigDecimal
18
+ numbers that aid to the interchangeability of floating point types. This
19
+ represent the only definition of identifiers outside the Flt namespace: the
20
+ methods Float.context() and BigDecimal.context() and some contants in Float.
21
+
22
+ This library is the successor of the ruby-decimal gem, that defined the
23
+ Decimal class for decimal floating point; that class has been renamed to
24
+ `Flt::DecNum` and support has been added for binary floating point and
25
+ tolerances.
26
+
27
+ The documentation for this package is available at
28
+ http://www.rubydoc.info/github/jgoizueta/flt/master
29
+
30
+ The code is at http://github.com/jgoizueta/flt/
31
+
32
+ ## DecNum
33
+
34
+ `Flt::DecNum` is a standards-compliant arbitrary precision decimal
35
+ floating-point type for Ruby. It is based on the Python Decimal class.
36
+
37
+ ## Standars compliance.
38
+
39
+ DecNum is designed to be conformant to the General Decimal Arithmetic
40
+ Specification and the revised IEEE 754 standard (IEEE 754-2008).
41
+
42
+ # Examples of use
43
+
44
+ To install the library use gem from the command line:
45
+
46
+ gem install flt
47
+
48
+ Then require the library in your code (if it fails you may need to `require
49
+ 'rubygems'` first)
50
+
51
+ ```ruby
52
+ require 'flt'
53
+ include Flt
54
+ ```
55
+
56
+ Now we can use the DecNum class simply like this:
57
+
58
+ ```ruby
59
+ puts DecNum(1)/DecNum(3) # -> 0.3333333333333333333333333333
60
+ ```
61
+
62
+ DecNum() is a constructor that can be used instead of DecNum.new()
63
+
64
+ ## Contexts
65
+
66
+ Contexts are environments for arithmetic operations. They govern precision,
67
+ set rules for rounding, determine which signals are treated as exceptions, and
68
+ limit the range for exponents.
69
+
70
+ Each thread has an active context that can be accessed like this:
71
+
72
+ ```ruby
73
+ puts DecNum.context.precision # -> 28
74
+ ```
75
+
76
+ The active context can be modified globally for the current thread:
77
+
78
+ ```ruby
79
+ DecNum.context.precision = 2
80
+ puts DecNum.context.precision # -> 2
81
+ puts DecNum(1)/DecNum(3) # -> 0.33
82
+ DecNum.context.precision += 7
83
+ puts DecNum.context.precision # -> 9
84
+ puts DecNum(1)/DecNum(3) # -> 0.333333333
85
+ ```
86
+
87
+ Or it can be altered locally inside a block:
88
+
89
+ ```ruby
90
+ DecNum.context do
91
+ DecNum.context.precision = 5
92
+ puts DecNum.context.precision # -> 5
93
+ end
94
+ puts DecNum.context.precision # -> 9
95
+ ```
96
+
97
+ The block for a local context can be passed the current context as an
98
+ argument:
99
+
100
+ ```ruby
101
+ DecNum.context do |local_context|
102
+ local_context.precision = 5
103
+ puts DecNum.context.precision # -> 5
104
+ end
105
+ puts DecNum.context.precision # -> 9
106
+ ```
107
+
108
+ A context object can also be used to define the local context:
109
+
110
+ ```ruby
111
+ my_context = DecNum::Context(precision: 20)
112
+ DecNum.context(my_context) do |context|
113
+ puts context.precision
114
+ end # -> 20
115
+ ```
116
+
117
+ And individual parameters can be assigned like this:
118
+
119
+ ```ruby
120
+ puts DecNum.context.precision # -> 9
121
+ puts DecNum.context.rounding # -> half_even
122
+ DecNum.context(rounding: :down) do |context|
123
+ puts context.precision # -> 9
124
+ puts context.rounding # -> down
125
+ end
126
+ ```
127
+
128
+ Contexts created with the `DecNum::Context()` constructor inherit from
129
+ DecNum::DefaultContext. Default context attributes can be established by
130
+ modifying that object:
131
+
132
+ ```ruby
133
+ DecNum::DefaultContext.precision = 10
134
+ DecNum.context = DecNum::Context(rounding: :half_up)
135
+ puts DecNum.context.precision # -> 10
136
+ ```
137
+
138
+ Note that a context object assigned to DecNum.context is copied, so it is not
139
+ altered through DecNum.context:
140
+
141
+ ```ruby
142
+ puts my_context.precision # -> 20
143
+ DecNum.context = my_context
144
+ DecNum.context.precision = 2
145
+ puts my_context.precision # -> 20
146
+ ```
147
+
148
+ So, DefaultContext is not altered when modifying DecNum.context.
149
+
150
+ Methods that use a context have an optional parameter to override the active
151
+ context (`DecNum.context`) :
152
+
153
+ ```ruby
154
+ DecNum.context.precision = 3
155
+ puts DecNum(1).divide(3) # -> 0.333
156
+ puts DecNum(1).divide(3, my_context) # -> 0.33333333333333333333
157
+ ```
158
+
159
+ Individual context parameters can also be overriden:
160
+
161
+ ```ruby
162
+ puts DecNum(1).divide(3, precision: 6) # -> 0.333333
163
+ ```
164
+
165
+ There are two additional predefined contexts `DecNum::ExtendedContext` and
166
+ DecNum::BasicContext that are not meant to be modified; they can be used to
167
+ achieve reproducible results. We will use `DecNum::ExtendedContext` in the
168
+ following examples:
169
+
170
+ ```ruby
171
+ DecNum.context = DecNum::ExtendedContext
172
+ ```
173
+
174
+ Most decimal operations can be executed by using either Context or DecNum
175
+ methods:
176
+
177
+ ```ruby
178
+ puts DecNum.context.exp(1) # -> 2.71828183
179
+ puts DecNum(1).exp # -> 2.71828183
180
+ ```
181
+
182
+ If using Context methods, values are automatically converted as if the
183
+ DecNum() constructor was used.
184
+
185
+ ## Rounding
186
+
187
+ Results are normally rounded using the precision (number of significant
188
+ digits) and rounding mode defined in the context.
189
+
190
+ ```ruby
191
+ DecNum.context.precision = 4
192
+ puts DecNum(1)/DecNum(3) # -> 0.3333
193
+ puts DecNum('1E20')-DecNum('1E-20') # -> 1.000E+20
194
+ DecNum.context.rounding = :half_up
195
+ puts +DecNum('100.05') # -> 100.1
196
+ DecNum.context.rounding = :half_even
197
+ puts +DecNum('100.05') # -> 100.0
198
+ ```
199
+
200
+ Note that input values are not rounded, only results; we use the plus operator
201
+ to force rounding here:
202
+
203
+ ```ruby
204
+ DecNum.context.precision = 4
205
+ x = DecNum('123.45678')
206
+ puts x # -> 123.45678
207
+ puts +x # -> 123.5
208
+ ```
209
+
210
+ Precision can be also set to 'exact' to avoid rounding, by using the exact
211
+ property or using a 0 precision. In exact mode results are never rounded and
212
+ results that have an infinite number of digits trigger the `DecNum::Inexact`
213
+ exception.
214
+
215
+ ```ruby
216
+ DecNum.context.exact = true
217
+ puts DecNum('1E20')-DecNum('1E-20') # -> 99999999999999999999.99999999999999999999
218
+ puts DecNum(16).sqrt # -> 4
219
+ puts DecNum(16)/DecNum(4) # -> 4
220
+ puts DecNum(1)/DecNum(3) # -> Exception : Flt::Num::Inexact
221
+
222
+ DecNum.context.precision = 5
223
+ puts DecNum('1E20')-DecNum('1E-20') # -> 1.0000E+20
224
+ puts DecNum(16).sqrt # -> 4
225
+ puts DecNum(16)/DecNum(4) # -> 4
226
+ puts DecNum(1)/DecNum(3) # -> 0.33333
227
+ ```
228
+
229
+ There are also some methods for explicit rounding that provide an interface
230
+ compatible with that of the Ruby `Float` class:
231
+
232
+ ```ruby
233
+ puts DecNum('101.5').round # -> 102
234
+ puts DecNum('101.5').round(0) # -> 102
235
+ puts DecNum('101.12345').round(2) # -> 101.12
236
+ puts DecNum('101.12345').round(-1) # -> 1.0E+2
237
+ puts DecNum('101.12345').round(places: 2) # -> 101.12
238
+ puts DecNum('101.12345').round(precision: 2) # -> 1.0E+2
239
+ puts DecNum('101.5').round(rounding: :half_up) # -> 102
240
+ puts DecNum('101.5').ceil # -> 102
241
+ puts DecNum('101.5').floor # -> 101
242
+ puts DecNum('101.5').truncate # -> 101
243
+ ```
244
+
245
+ ## Special values
246
+
247
+ In addition to finite numbers, a DecNum object can represent some special
248
+ values:
249
+ * Infinity (+Infinity, -Infinity). The method DecNum#infinite? returns true
250
+ for these to values. DecNum.infinity DecNum.infinity(-1) can be used to
251
+ get these values.
252
+ * NaN (not a number) represents undefined results. The method DecNum#nan?
253
+ returns true for it and DecNum.nan can be used to obtain it. There is a
254
+ variant, sNaN (signaling NaN) that causes an invalid operation condition
255
+ if used; it can be detected with DecNum.snan?. A NaN can also include
256
+ diagnostic information in its sign and coefficient.
257
+
258
+ Any of the special values can be detected with DecNum#special? Finite numbers
259
+ can be clasified with these methods:
260
+ * DecNum#zero? detects a zero value (note that there are two zero values: +0
261
+ and -0)
262
+ * DecNum#normal? detects normal values: those whose adjusted exponents are
263
+ not less than @emin@.
264
+ * DecNum#subnormal? detects subnormal values: those whose adjusted exponents
265
+ are less than @emin@.
266
+
267
+ ## Exceptions
268
+
269
+ Exceptional conditions that may arise during operations have corresponding
270
+ classes that represent them:
271
+ * DecNum::InvalidOperation
272
+ * DecNum::DivisionByZero
273
+ * DecNum::DivisionImpossible
274
+ * DecNum::DivisionUndefined
275
+ * DecNum::Inexact
276
+ * DecNum::Overflow
277
+ * DecNum::Underflow
278
+ * DecNum::Clamped
279
+ * DecNum::InvalidContext
280
+ * DecNum::Rounded
281
+ * DecNum::Subnormal
282
+ * DecNum::ConversionSyntax
283
+
284
+ For each condition, a flag and a trap (boolean values) exist in the context.
285
+ When a condition occurs, the corresponding flag in the context takes the value
286
+ true (and remains set until cleared) and a exception is raised if the
287
+ corresponding trap has the value true.
288
+
289
+ ```ruby
290
+ DecNum.context.traps[DecNum::DivisionByZero] = false
291
+ DecNum.context.flags[DecNum::DivisionByZero] = false
292
+ puts DecNum(1)/DecNum(0) # -> Infinity
293
+ puts DecNum.context.flags[DecNum::DivisionByZero] # -> true
294
+ DecNum.context.traps[DecNum::DivisionByZero] = true
295
+ puts DecNum(1)/DecNum(0) # -> Exception : Flt::Num::DivisionByZero
296
+ ```
297
+
298
+ ## Numerical conversion
299
+
300
+ By default, `DecNum` is interoperable with `Integer` and `Rational`. Conversion
301
+ happens automatically to operands:
302
+
303
+ ```ruby
304
+ puts DecNum('0.1') + 1 # -> 1.1
305
+ puts 7 + DecNum('0.2') # -> 7.2
306
+ puts Rational(5,2) + DecNum('3') # -> 5.5
307
+ ```
308
+
309
+ Conversion can also be done explicitly with the DecNum constructor:
310
+
311
+ ```ruby
312
+ puts DecNum(7) # -> 7
313
+ puts DecNum(Rational(1,10)) # -> 0.1
314
+ ```
315
+
316
+ Converting a `DecNum` to other numerical types can be done with specific
317
+ Ruby-style methods. (note the truncated result of `to_i`)
318
+
319
+ ```ruby
320
+ puts DecNum('1.1').to_i # -> 1
321
+ puts DecNum('1.1').to_r # -> 11/10
322
+ ```
323
+
324
+ Or with a generic method:
325
+
326
+ ```ruby
327
+ puts DecNum('1.1').convert_to(Integer) # -> 1
328
+ puts DecNum('1.1').convert_to(Rational) # -> 11/10
329
+ ```
330
+
331
+ Thera are also GDAS style conversion operations:
332
+
333
+ ```ruby
334
+ puts DecNum('1.1').to_integral_value # -> 1
335
+ ```
336
+
337
+ And conversion is also possible to `Float`:
338
+
339
+ ```ruby
340
+ puts DecNum('1.1').to_f # -> 1.1
341
+ puts DecNum('1.1').convert_to(Float) # -> 1.1
342
+ puts Float(DecNum('1.1')) # -> 1.1
343
+ ```
344
+
345
+ Types with predefined bidirectional conversion (`Integer` and `Rational`) can be
346
+ operated with `DecNum` on either side of an operator, and the result will be a
347
+ `DecNum`. For `Float` there is no predefined bidirectional conversion (see below
348
+ how to define it) and the result of an operation between `DecNum` and `Float` will
349
+ be of type `Float`.
350
+
351
+ ```ruby
352
+ puts (DecNum('1.1') + 2.0).class # -> Float
353
+ puts (2.0 + DecNum('1.1')).class # -> Float
354
+ ```
355
+
356
+ The conversion system is extensible. For example, we can include BigDecimal
357
+ into it by defining suitable conversion procedures:
358
+
359
+ ```ruby
360
+ DecNum.context.define_conversion_from(BigDecimal) do |x, context|
361
+ DecNum(x.to_s)
362
+ end
363
+ DecNum.context.define_conversion_to(BigDecimal) do |x|
364
+ BigDecimal.new(x.to_s)
365
+ end
366
+ ```
367
+
368
+ Now we can mix `BigDecimals` and `Decimals` in expressions and convert from `DecNum`
369
+ to `BigDecimal`:
370
+
371
+ ```ruby
372
+ puts BigDecimal.new('1.1') + DecNum('2.2') # -> 3.3
373
+ puts DecNum('1.1').convert_to(BigDecimal) # -> 0.11E1
374
+ ```
375
+
376
+ Note that the conversions are defined in a `Context` object and will be
377
+ available only when that context applies. That way we can define conversions
378
+ for specific purposes without affecting a program globally.
379
+
380
+ As another example consider conversion from Float to DecNum, which is not
381
+ defined by default because it can be defined in different ways depending on
382
+ the purpose.
383
+
384
+ A `Float` constant such as 0.1 defines a `Float` object which has a numerical
385
+ value close to, but not exactly 1/10. When converting that `Float` to `DecNum` we
386
+ could decide to preserve the exact numerical value of the number or try to
387
+ find a simple decimal expression within a given tolerance. If we take the
388
+ first approach we can define this conversion:
389
+
390
+ ```ruby
391
+ DecNum.context.define_conversion_from(Float) do |x, context|
392
+ s,e = Math.frexp(x)
393
+ s = Math.ldexp(s, Float::MANT_DIG).to_i
394
+ e -= Float::MANT_DIG
395
+ DecNum(s*(Float::RADIX**e))
396
+ end
397
+ ```
398
+
399
+ Note that the conversion we've defined depends on the context precision:
400
+
401
+ ```ruby
402
+ DecNum.local_context(precision: 20) { puts DecNum(0.1) } # -> 0.10000000000000000555
403
+ DecNum.local_context(precision: 12) { puts DecNum(0.1) } # -> 0.100000000000
404
+ DecNum.local_context(exact: true) { puts DecNum(0.1) } # -> 0.1000000000000000055511151231257827021181583404541015625
405
+ ```
406
+
407
+ A different approach for Float to DecNum conversion is to find the shortest
408
+ (fewer digits) DecNum that rounds to the Float with the binary precision that
409
+ the Float has. We will assume that the DecNum to Float conversion done with
410
+ the rounding mode of the DecNum context. The BinNum class has a method to
411
+ perform this kind of conversion, so we will use it.
412
+
413
+ ```ruby
414
+ DecNum.context.define_conversion_from(Float) do |x, dec_context|
415
+ BinNum.context(:rounding=>dec_context.rounding) do |bin_context|
416
+ BinNum(x).to_decimal
417
+ end
418
+ end
419
+ ```
420
+
421
+ The result is independent of the context precision.
422
+
423
+ ```ruby
424
+ puts DecNum(0.1) # -> 0.1
425
+ puts DecNum(1.0/3) # -> 0.3333333333333333
426
+ ```
427
+
428
+ This conversion gives the results expected most of the time, but it must be
429
+ noticed that there must be some compromise, because different decimal literals
430
+ convert to the same `Float` value:
431
+
432
+ ```ruby
433
+ puts DecNum(0.10000000000000001) # -> 0.1
434
+ ```
435
+
436
+ There's also some uncertainty because the way the Ruby interpreter parses
437
+ Float literals may not be well specified; in the usual case (IEEE Double
438
+ Floats and round-to-even) the results will be as expected (correctly rounded
439
+ Floats), but some platforms may behave differently.
440
+
441
+ The `BinNum` also a instance method `to_decimal_exact` to perform the previous
442
+ 'exact' conversion, that could have be written:
443
+
444
+ ```ruby
445
+ DecNum.context.define_conversion_from(Float) do |x, context|
446
+ DecNum.context(context) do
447
+ BinNum(x).to_decimal_exact
448
+ end
449
+ end
450
+ ```
451
+
452
+ ## Abbreviation
453
+
454
+ The use of DecNum can be made less verbose by requiring:
455
+
456
+ ```ruby
457
+ require 'flt/d'
458
+ ```
459
+
460
+ This file defines `D` as a synonym for `DecNum`:
461
+
462
+ ```ruby
463
+ D.context.precision = 3
464
+ puts +D('1.234') # -> 1.23
465
+ ```
466
+
467
+ Some convenient methods are added to numeric classes by requiring the optional
468
+ [flt/sugar.rb](lib/flt/sugar_rb.html). This must be explicitely required
469
+ because it could cause conflicts with other extensions of these classes.
470
+
471
+ ```ruby
472
+ require 'flt/sugar'
473
+
474
+ puts 34.odd? # -> false
475
+ puts 34.even? # -> true
476
+ puts 0.1.split.inspect # -> [1, 7205759403792794, -56]
477
+ puts (-0.1).sign # -> -1
478
+ ```
479
+
480
+ A shortcut notation for DecNum is defined in this file (based on an idea by
481
+ [coderrr](http://coderrr.wordpress.com) which allows exact definitions with
482
+ almost literal decimal syntax (note the underscore after the dot.)
483
+
484
+ ```ruby
485
+ puts 10._123456789123456789 # -> 10.123456789123456789
486
+ ```
487
+
488
+ Additional underscores can be used to separate digits at any place except
489
+ before the decimal point:
490
+
491
+ ```ruby
492
+ puts 100_000._000_001 # -> 100000.000001
493
+ puts 100_000._000_001.class # -> Flt::DecNum
494
+ ```
495
+
496
+ But note that `100_000.000_001` is a valid `Float` (it's not a `DecNum` because
497
+ there isn't an underscore just after the decimal point):
498
+
499
+ ```ruby
500
+ puts 100_000.000_001 # -> 100000.000001
501
+ puts 100_000.000_001.class # -> Float
502
+ ```
503
+
504
+ There's also one important caveat with this notation: negative numbers with a
505
+ zero integral part must be parenthesed (otherwise the minus has no effect
506
+ because it affects only the null integer part):
507
+
508
+ ```ruby
509
+ puts -0._5 # -> 0.5
510
+ puts -(0._5) # -> -0.5
511
+ ```
512
+
513
+ ## Error analysis
514
+
515
+ The DecNum#ulp() method returns the value of a "unit in the last place" for a
516
+ given number under the current context.
517
+
518
+ ```ruby
519
+ D.context.precision = 4
520
+ puts D('1.5').ulp # -> 0.001
521
+ puts D('1.5E10').ulp # -> 1E+7
522
+ ```
523
+
524
+ Whe can compute the error in ulps of an approximation `aprx` to correclty
525
+ rounded value `exct` with:
526
+
527
+ ```ruby
528
+ def ulps(exct, aprx)
529
+ (aprx-exct).abs/exct.ulp
530
+ end
531
+
532
+ puts ulps(DecNum('0.5000'), DecNum('0.5003')) # -> 3
533
+ puts ulps(DecNum('0.5000'), DecNum('0.4997')) # -> 3
534
+
535
+ puts ulps(DecNum('0.1000'), DecNum('0.1003')) # -> 3E+1
536
+ puts ulps(DecNum('0.1000'), DecNum('0.0997')) # -> 3E+1
537
+
538
+ puts ulps(DecNum(1), DecNum(10).next_minus) # -> 8.999E+4
539
+ puts ulps(DecNum(1), DecNum(10).next_plus) # -> 9.01E+4
540
+ ```
541
+
542
+ Note that in the definition of ulps we use exct.ulp. If we had use aprx.ulp
543
+ DecNum(10).next_plus would seem to be a better approximation to DecNum(1) than
544
+ DecNum(10).next_minus. (Admittedly, such bad approximations should not be
545
+ common.)
546
+
547
+ ## BinNum Input/Output
548
+
549
+ BinNum can be defined with a decimal string literal and converted to one with
550
+ to_s, as DecNum, but since this involves a change of base these are inexact
551
+ operations subject to some specific precision limits.
552
+
553
+ If we define the number with a binary literal, no base conversion is involved
554
+ and the result is exactly defined; here we define a number with just one bit
555
+ of precision:
556
+
557
+ ```ruby
558
+ x = BinNum('0.001', base: 2)
559
+ puts x.number_of_digits # -> 1
560
+ puts x.to_s(base: 2) # -> 0.001
561
+ ```
562
+
563
+ Note that we could have defined it with more precision, e.g.
564
+
565
+ ```ruby
566
+ y = BinNum('0.001000', base: 2)
567
+ puts y.number_of_digits # -> 4
568
+ puts y.to_s(base: 2) # -> 0.001000
569
+ ```
570
+
571
+ But let's get back to our one bit quantity, x, and convert it to a decimal
572
+ string. Since the internal precision is only one bit it contains very little
573
+ information:
574
+
575
+ ```ruby
576
+ puts x # -> 0.1
577
+ ```
578
+
579
+ We can obtain more digits with the :all_digits option which show all the
580
+ decimal digits that are significative for the given precision of 1 bit:
581
+
582
+ ```ruby
583
+ puts x.to_s(all_digits: true) # -> 0.12
584
+ ```
585
+
586
+ We can also obtain the exact value of x by using the Num.convert_exact method
587
+ to convert it to decimal (base 10):
588
+
589
+ ```ruby
590
+ puts Num.convert_exact(x,10) # -> 0.125
591
+ ```
592
+
593
+ Let's convert the default decimal output back to another BinNum which will
594
+ preserve its precision:
595
+
596
+ ```ruby
597
+ y = BinNum(x.to_s)
598
+ ```
599
+
600
+ The result may seem ok:
601
+
602
+ ```ruby
603
+ puts y # -> 0.1
604
+ ```
605
+
606
+ But is not exactly what we originally had:
607
+
608
+ ```ruby
609
+ puts y==x # -> false
610
+ puts y # -> 0.1
611
+ puts y.number_of_digits # -> 5
612
+ puts y.to_s(base: 2) # -> 0.00011010
613
+ ```
614
+
615
+ The new value y has gained some digits because of the intermediate conversion
616
+ to decimal: one decimal digit contains more information than one bit, and the
617
+ result shows that.
618
+
619
+ If we wanted to preserve exactly the number we should have done this:
620
+
621
+ ```ruby
622
+ y = BinNum(x.to_s, :fixed, precision: x.number_of_digits)
623
+ puts y==x # -> true
624
+ ```
625
+
626
+ To preserve the value we had to explicitly determine how many bits should y
627
+ have.
628
+
629
+ With the :fixed options the number produced by BinNum is rounded to the
630
+ context precision (which can be overriden as in the example by other options):
631
+
632
+ ```ruby
633
+ puts BinNum(x.to_s, :fixed, precision: 32).to_s(base: 2) # -> 0.00011001100110011001100110011001101
634
+ puts BinNum(x.to_s, :fixed, precision: 1).to_s(base: 2) # -> 0.001
635
+ ```
636
+
637
+ Note also that if we normalize a value we will change it's precision to that
638
+ of the context:
639
+
640
+ ```ruby
641
+ puts x.number_of_digits # -> 1
642
+ puts x.normalize.number_of_digits # -> 53
643
+ puts x.normalize.to_s # -> 0.125
644
+ ```
645
+
646
+ ## Mathematical functions
647
+
648
+ There are two mathematical functions modules analogous to Ruby's Math for
649
+ Float, Flt::DecNum::Math and Flt::BinNum::Math. Currently they consist of
650
+ basic trigonometric functions, including hypot, logarithms and the exponential
651
+ function, and the constants e and pi.
652
+
653
+ Its functions can be accessed in a number of ways:
654
+
655
+ ```ruby
656
+ require 'flt/math'
657
+ DecNum.context(precision: 10) do |context|
658
+ # As module functions, using the current context for the enclosing Num class:
659
+ puts DecNum::Math.sin(1)*DecNum::Math.pi # -> 2.643559064
660
+ # As functions of a context object:
661
+ puts context.sin(1)*context.pi # -> 2.643559064
662
+ # Through a math block:
663
+ puts DecNum.context.math{sin(1)*pi} # -> 2.643559064
664
+ puts DecNum.math{sin(1)*pi} # -> 2.643559064
665
+ # And can be *included* to be used as private instance methods:
666
+ include DecNum::Math
667
+ puts sin(1)*pi # -> 2.643559064
668
+ end
669
+ ```
670
+
671
+ ## More Information
672
+
673
+ * Decimal Floating point type: see the base Flt::Num class and the
674
+ Flt::DecNum class
675
+ * Binary Floating point type: see the base Flt::Num class and the
676
+ Flt::BinNum class
677
+ * Floating Point Contexts: see documentation for classes
678
+ Flt::Num::ContextBase, Flt::DecNum::Context and Flt::BinNum::Context
679
+ * Floating Point Tolerance: see the
680
+ [flt/tolerance.rb](lib/flt/tolerance_rb.html) file and the Flt::Tolerance
681
+ class
682
+ * Constructors: see Flt.DecNum(), Flt.BinNum() and Flt.Tolerance().
683
+ * Trigonometry functions: see Flt::Trigonometry.
684
+ * Complex number support: see the [flt/complex.rb](lib/flt/complex_rb.html)
685
+ file
686
+
687
+ # DecNum vs BigDecimal
688
+
689
+ DecNum solves some of the difficulties of using BigDecimal.
690
+
691
+ One of the major problems with BigDecimal is that it's not easy to control the
692
+ number of significant digits of the results. While addition, subtraction and
693
+ multiplication are exact (unless a limit is used), divisions will need to be
694
+ passed precision explicitly or else an indeterminate number of significant
695
+ digits will be lost. Part of the problem is that numbers don't keep track of
696
+ its precision (0.1000 is not distinguishable from 0.1.)
697
+
698
+ With DecNum, Context objects are used to specify the exact number of digits to
699
+ be used for all operations making the code cleaner and the results more easily
700
+ predictable.
701
+
702
+ ```ruby
703
+ DecNum.context.precision = 10
704
+ puts DecNum(1)/DecNum(3)
705
+ ```
706
+
707
+ Contexts are thread-safe and can be used for individual operations:
708
+
709
+ ```ruby
710
+ puts DecNum(1).divide(DecNum(e), DecNum::Context(precision: 4))
711
+ ```
712
+
713
+ Which can be abbreviated:
714
+
715
+ ```ruby
716
+ puts DecNum(1).divide(DecNum(e), precision: 4)
717
+ ```
718
+
719
+ Or use locally in a block without affecting other code:
720
+
721
+ ```ruby
722
+ DecNum.context {
723
+ DecNum.context.precision = 3
724
+ puts DecNum(1)/DecNum(3)
725
+ }
726
+ puts DecNum.context.precision
727
+ ```
728
+
729
+ Which can also be abbreviated:
730
+
731
+ ```ruby
732
+ DecNum.context(precision: 3) { puts DecNum(1)/DecNum(3) }
733
+ ```
734
+
735
+ This allows in general to write simpler code; e.g. this is an exponential
736
+ function, adapted from the 'recipes' in Python's Decimal:
737
+
738
+ ```ruby
739
+ def exp(x, c=nil)
740
+ i, lasts, s, fact, num = 0, 0, 1, 1, 1
741
+ DecNum.context(c) do |context|
742
+ context.precision += 2
743
+ while s != lasts
744
+ lasts = s
745
+ i += 1
746
+ fact *= i
747
+ num *= x
748
+ s += num / fact
749
+ end
750
+ end
751
+ return +s
752
+ end
753
+ ```
754
+
755
+ The final unary + applied to the result forces it to be rounded to the current
756
+ precision (because we have computed it with two extra digits) The result of
757
+ this method does not have trailing non-significant digits, as is common with
758
+ BigDecimal (e.g. in the exp implementation available in the standard Ruby
759
+ library, in bigdecimal/math)
760
+
761
+ # Roadmap
762
+
763
+ * Trigonometry optimizations
764
+ * Implement the missing GDA functions: rotate, shift, trim, and, or, xor,
765
+ invert, max, min, maxmag, minmag, comparetotal, comparetotmag