flt 1.4.4 → 1.4.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b31b19298dc561379a1bb087187ba69da8d959ab
4
- data.tar.gz: b26b4ff187ec92bd51198b274666babf5123c856
3
+ metadata.gz: 7de71640b6e679c521d717895549d5858393bf9a
4
+ data.tar.gz: 20405872b9008205ffd8f4af67b2197be583539f
5
5
  SHA512:
6
- metadata.gz: 561ae33a6932265a5f6e708405c485c1d684f42db179c8575f5949bf78a7d25316a1ca5da03de911cfe7f82f8ee3c6e359a9f68d74c4862c5319a7cb06fa18bc
7
- data.tar.gz: c29f03d82d8c9513d11318ce2f66fbcac5507757acc12fa7b4c01b0e65734583a1f244566d18626662ff35d57a06ffee1e0ac4bae4363d95978ed1b70ce7fb5f
6
+ metadata.gz: d5b4929799d05f048bf51827ad8dd3704467d71e4d93b996e3841c2a85d098770b20f70a7dd75b1dd86d4975d05c1232a9669e826eea70370f03e93dd61ccca6
7
+ data.tar.gz: a4f6ee9f59a5e6c70c128f902465927bd68a07858871a6dff468fa78a5615d5048e6c2e4302210b60ca749b1d54dabc8175220ec617fb888e7cbba1517b68791
@@ -1,3 +1,8 @@
1
+ == 1.4.5 2015-03-04
2
+
3
+ * New feature
4
+ - options :simplified, :exact and :format added to Num#to_s, Num#format
5
+
1
6
  == 1.4.4 2015-03-03
2
7
 
3
8
  * Bugfix
@@ -3192,64 +3192,9 @@ class Num < Numeric
3192
3192
  return product.add(third, context)
3193
3193
  end
3194
3194
 
3195
- # Convert to a text literal in the specified base (10 by default).
3196
- #
3197
- # If the output base is the floating-point radix, the rendered value is the exact value of the number,
3198
- # showing trailing zeros up to the stored precision.
3199
- #
3200
- # With bases different from the radix, the floating-point number is treated
3201
- # as an approximation with a precision of number_of_digits, representing any value
3202
- # within its rounding range. In that case, this method always renders
3203
- # that aproximated value in other base without introducing additional precision.
3204
- #
3205
- # The resulting text numeral is such that it has as few digits as possible while
3206
- # preserving the original while if converted back to the same type of floating-point value with
3207
- # the same context precision that the original number had (number_of_digits).
3208
- #
3209
- # To render the exact value of a Num x in a different base b this can be used
3210
- # Flt::Num.convert_exact(x, b).to_s(:base=>b)
3211
- # Or, to represent a BinNum x in decimal:
3212
- # x.to_decimal_exact(:exact=>true).to_s
3213
- #
3214
- # Options:
3215
- # :base output base, 10 by default
3216
- #
3217
- # :rounding is used to override the context rounding, but it's main use is specify :nearest
3218
- # as the rounding-mode, which means that the text literal will have enough digits to be
3219
- # converted back to self in any round-to_nearest rounding mode. Otherwise only enough
3220
- # digits for conversion in a specific rounding mode are produced.
3221
- #
3222
- # :all_digits if true all significant digits are shown. A digit
3223
- # is considered as significant here if when used on input, cannot
3224
- # arbitrarily change its value and preserve the parsed value of the
3225
- # floating point number.
3226
- # Using all_digits will show trailing zeros up to the precision of the floating-point, so
3227
- # the output will preserve the input precision. With all_digits and the :down rounding-mod
3228
- # (truncation), the result will be the exact value floating-point value in the output base
3229
- # (if it is conmensurable with the floating-point base).
3195
+ # Representation as text of a number: this is an alias of Num#format
3230
3196
  def to_s(*args)
3231
- eng=false
3232
- context=nil
3233
-
3234
- # admit legacy arguments eng, context in that order
3235
- if [true,false].include?(args.first)
3236
- eng = args.shift
3237
- end
3238
- if args.first.is_a?(Num::ContextBase)
3239
- context = args.shift
3240
- end
3241
- # admit also :eng to specify the eng mode
3242
- if args.first == :eng
3243
- eng = true
3244
- args.shift
3245
- end
3246
- raise TypeError, "Invalid arguments to #{num_class}#to_s" if args.size>1 || (args.size==1 && !args.first.is_a?(Hash))
3247
- # an admit arguments through a final parameters Hash
3248
- options = args.first || {}
3249
- context = options.delete(:context) if options.has_key?(:context)
3250
- eng = options.delete(:eng) if options.has_key?(:eng)
3251
-
3252
- format(context, options.merge(:eng=>eng))
3197
+ format *args
3253
3198
  end
3254
3199
 
3255
3200
  # Raises to the power of x, to modulo if given.
@@ -3754,42 +3699,133 @@ class Num < Numeric
3754
3699
 
3755
3700
  end
3756
3701
 
3757
- # Convert to a text literal in the specified base. If the result is
3758
- # converted to BinNum with the specified context rounding and the
3759
- # same precision that self has (self.number_of_digits), the same
3760
- # number will be produced.
3702
+ # Internal method to allow format (and to_s) to admit legacy
3703
+ # parameters.
3704
+ def format_legacy_parameters(*args)
3705
+ eng = false
3706
+ context = nil
3707
+
3708
+ # formerly the eng value and the context could be passed
3709
+ # as separate values in that order
3710
+ if [true,false].include?(args.first)
3711
+ eng = args.shift
3712
+ end
3713
+ if args.first.is_a?(Num::ContextBase)
3714
+ context = args.shift
3715
+ end
3716
+
3717
+ # and the :eng symbol could be passed to enable it
3718
+ if args.first == :eng
3719
+ eng = true
3720
+ args.shift
3721
+ end
3722
+
3723
+ if args.size > 1 || (args.size == 1 && !args.first.is_a?(Hash))
3724
+ raise TypeError, "Invalid arguments to #{num_class}#format"
3725
+ end
3726
+
3727
+ # now all arguments should be passed in a hash
3728
+ options = args.first || {}
3729
+ { :eng => eng, :context => context }.merge(options)
3730
+ end
3731
+ private :format_legacy_parameters
3732
+
3733
+ # Conversion to a text literal
3761
3734
  #
3762
- # Options:
3763
- # :base output base, 10 by default
3735
+ # The base of the produced literal can be specified by the :base option,
3736
+ # which is 10 by default.
3764
3737
  #
3765
- # :rounding is used to override the context rounding, but it's main use is specify :nearest
3766
- # as the rounding-mode, which means that the text literal will have enough digits to be
3767
- # converted back to self in any round-to_nearest rounding mode. Otherwise only enough
3768
- # digits for conversion in a specific rounding mode are produced.
3738
+ # ## Same base
3769
3739
  #
3770
- # :all_digits if true all significant digits are shown. A digit
3771
- # is considere as significant here if when used on input, cannot
3740
+ # If the output base is the floating-point radix the actual internal value
3741
+ # of the number is produced, by default showing trailing zeros up to the
3742
+ # stored precision, e.g. 0.100.
3743
+ #
3744
+ # The :simplified option can be used in this case to remove the trailing
3745
+ # zeros, producing 0.1. The actual effect of this options is to regard
3746
+ # the number an *approximation* (see below) and show only as few digits
3747
+ # as possible while making sure that the result rounds back to the original
3748
+ # value (if rounded to its original precision).
3749
+ #
3750
+ # With the :all_digits option the number will be considered also an
3751
+ # approximation and all its 'significant' digits are shown. A digit
3752
+ # is considered significant here if when used on input, cannot
3772
3753
  # arbitrarily change its value and preserve the parsed value of the
3773
- # floating point number.
3754
+ # floating point number (to the original precision).
3755
+ # In our case the result would be 0.1000, because the additional shown 0
3756
+ # is a digit that if changed arbitrarily could make the number round to
3757
+ # a different value from the original 0.100.
3758
+ #
3759
+ # ## Different bases
3760
+ #
3761
+ # For bases different from the radix, by default the floating-point number
3762
+ # is treated as an approximation and is redendered as if with the
3763
+ # :simplified option mention above.
3764
+ #
3765
+ # The :all_digits option acts as in the same-base case. Note that
3766
+ # aproximated values are formatted without introducing additional precision.
3767
+ #
3768
+ # The :exact options can be used to render the exact value in the output
3769
+ # base (by using Flt::Num.convert_exact)
3770
+ #
3771
+ # ## All available options:
3772
+ #
3773
+ # :base defines the output base, 10 by default. If the output base is defined
3774
+ # as :hex_bin, then the %A/%a format of printf is used, which shows the
3775
+ # significand as an hexadecimal number and the binary exponent in decimal.
3774
3776
  #
3775
- # :output_rounding implies :all_digits; it defines the rounding mode for the output,
3776
- # that will show all significant digits rounded.
3777
- # If it is not passed and :all_digits is true, then :rounding or the context rounding mode
3778
- # will be used.
3777
+ # :exp_base allows to define a different base for the exponent
3778
+ # than for the coefficient, as occurs with the :hex_bin base; the base for the
3779
+ # coefficient must be a power of that of the exponent.
3779
3780
  #
3780
- # Note that when :base is different from the floating point radix,
3781
- # we're regarding the floating point number x
3782
- # as an approximation with x.number_of_digits precision and showing that
3783
- # inexact value in decimal without introducing additional precision.
3781
+ # :rounding is used to override the context rounding. It allows to
3782
+ # specify the :nearest as the rounding-mode, which means that the text
3783
+ # literal will have enough digits to be converted back to the original value
3784
+ # in any of the round-to-nearest rounding modes. Otherwise only enough
3785
+ # digits for conversion in a specific rounding mode are produced.
3786
+ #
3787
+ # :all_digits makes all 'significant' digits visible, considering
3788
+ # the number approximate as explained below.
3789
+ # Using :all_digits will show trailing zeros up to the precision of the
3790
+ # floating-point, so the output will preserve the input precision.
3791
+ # With :all_digits and the :down rounding-mode (truncation), the result will
3792
+ # be the exact value floating-point value in the output base
3793
+ # (if it is conmensurable with the floating-point radix).
3794
+ #
3795
+ # :simplify shows only the digits necessary to preserve the original value
3796
+ # (which is the default when output base differs from radix)
3797
+ #
3798
+ # :exact interprets the number as an exact value, not an approximation so
3799
+ # that the exact original value can be rendered in a different base.
3784
3800
  #
3785
- # If the exact value of the number expressed in other base is desired (we consider
3786
- # the Flt an exact number), this can be done with Num.convert_exact.
3801
+ # :format specifies the numeric format:
3787
3802
  #
3788
- # The :hex_bin option produces the %A/%a format of printf, which sho2 the significand
3789
- # as an hexadecimal number and the binary exponent in decimal.
3803
+ # * :sci selects scientific notation
3804
+ # * :fix selects fixed format (no exponent is shown)
3805
+ # * :eng is equivalent to :sci and setting the :eng option
3806
+ # * :auto selects :fix or :sci automatically (the default)
3790
3807
  #
3791
- def format(num_context, options={})
3792
- # TODO: support options (base, all_digits, any_rounding, eng) and context options in the same hash
3808
+ # ## Note: approximate vs exact values
3809
+ #
3810
+ # In order to represent a floating point value `x`, we can take
3811
+ # two approaches:
3812
+ #
3813
+ # * Consider it an *exact* value, namely:
3814
+ # `x.sign*x.integral_significand*radix**x.integral_exponent`
3815
+ # * Consider it an *approximation* with its particular precision,
3816
+ # that represents any value within its rounding range.
3817
+ # The exact rounding range depends on the rounding mode used to create
3818
+ # the floating point mode; in the case of nearest rounding it is the
3819
+ # set of numbers that line closer to the floating point value than to
3820
+ # any other floating point value.
3821
+ #
3822
+ def format(*args)
3823
+ options = format_legacy_parameters(*args)
3824
+
3825
+ format_mode = options[:format] || :auto
3826
+ max_leading_zeros = 6
3827
+
3828
+ num_context = options[:context]
3793
3829
  output_radix = options[:base] || 10
3794
3830
  output_exp_radix = options[:exp_base]
3795
3831
  if output_radix == :hex_bin
@@ -3801,7 +3837,13 @@ class Num < Numeric
3801
3837
  rounding = options[:rounding]
3802
3838
  all_digits = options[:all_digits]
3803
3839
  eng = options[:eng]
3840
+ if format_mode == :eng
3841
+ format_mode = :sci
3842
+ eng = true
3843
+ end
3804
3844
  output_rounding = options[:output_rounding]
3845
+ exact = options[:exact]
3846
+ simplified = options[:simplified]
3805
3847
  all_digits ||= output_rounding
3806
3848
 
3807
3849
  sgn = @sign<0 ? '-' : ''
@@ -3827,6 +3869,13 @@ class Num < Numeric
3827
3869
  end
3828
3870
  end
3829
3871
 
3872
+ if output_radix != num_class.radix && exact && !all_digits && !simplified
3873
+ value = Num[output_radix].context(exact: true){ Num.convert_exact(self, output_radix) }
3874
+ options = options.dup
3875
+ options.delete :context
3876
+ return value.format(options)
3877
+ end
3878
+
3830
3879
  if output_exp_radix == num_class.radix && !all_digits && output_radix != output_exp_radix
3831
3880
  if first_digit_1
3832
3881
  # make the first digit a 1
@@ -3847,7 +3896,7 @@ class Num < Numeric
3847
3896
  n_ds = ds.size
3848
3897
  leftdigits = exp + n_ds
3849
3898
  exp_radix = num_class.radix
3850
- elsif output_radix == num_class.radix && !all_digits && output_radix == output_exp_radix
3899
+ elsif output_radix == num_class.radix && !all_digits && output_radix == output_exp_radix && !simplified
3851
3900
  # show exactly inner representation and precision
3852
3901
  ds = @coeff.to_s(output_radix)
3853
3902
  n_ds = ds.size
@@ -3898,8 +3947,16 @@ class Num < Numeric
3898
3947
  n_ds = ds.size
3899
3948
  end
3900
3949
  else
3901
- # TODO: DRY (this code is duplicated in num_class#format)
3902
- if exp<=0 && leftdigits>-6
3950
+ if format_mode == :auto
3951
+ fix = exp <= 0
3952
+ fix &&= leftdigits > -max_leading_zeros if max_leading_zeros
3953
+ if fix
3954
+ format_mode = :fix
3955
+ else
3956
+ format_mode = :sci
3957
+ end
3958
+ end
3959
+ if format_mode == :fix
3903
3960
  dotplace = leftdigits
3904
3961
  elsif !eng
3905
3962
  dotplace = 1
@@ -1,3 +1,3 @@
1
1
  module Flt
2
- VERSION = "1.4.4"
2
+ VERSION = "1.4.5"
3
3
  end
@@ -0,0 +1,80 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
+
3
+ class TestFormat < Test::Unit::TestCase
4
+
5
+ def setup
6
+ initialize_context
7
+ end
8
+
9
+ def test_same_base_format
10
+ value = DecNum('0.100', :free)
11
+ assert_equal '0.100', value.to_s
12
+ assert_equal '0.1', value.to_s(:simplified => true)
13
+ assert_equal '0.1000', value.to_s(:all_digits => true)
14
+
15
+ value = DecNum('1.00', :free)
16
+ assert_equal '1.00', value.to_s
17
+ assert_equal '1', value.to_s(:simplified => true)
18
+ assert_equal '1.000', value.to_s(:all_digits => true)
19
+
20
+ value = DecNum('0.101', :free)
21
+ assert_equal '0.101', value.to_s
22
+ assert_equal '0.101', value.to_s(:simplified => true)
23
+ assert_equal '0.1010', value.to_s(:all_digits => true)
24
+
25
+ value = DecNum('0.100', :free)
26
+ assert_equal '0.100', value.to_s
27
+ assert_equal '0.1', value.to_s(:simplified => true)
28
+ assert_equal '0.1000', value.to_s(:all_digits => true)
29
+
30
+ value = DecNum('0.100E-10', :free)
31
+ assert_equal '1.00E-11', value.to_s
32
+ assert_equal '1E-11', value.to_s(:simplified => true)
33
+ assert_equal '1.000E-11', value.to_s(:all_digits => true)
34
+
35
+ value = DecNum('0.100E+10', :free)
36
+ assert_equal '1.00E+9', value.to_s
37
+ assert_equal '1E+9', value.to_s(:simplified => true)
38
+ assert_equal '1.000E+9', value.to_s(:all_digits => true)
39
+ end
40
+
41
+ def test_mixed_base_format
42
+ value = BinNum.context(precision: 6){ BinNum('0.1', :fixed)}
43
+ assert_equal '0.099609375', value.to_s(:exact => true)
44
+ assert_equal '0.1', value.to_s
45
+ assert_equal '0.100', value.to_s(:all_digits => true)
46
+ assert_equal '0.099609375', value.to_s(:all_digits => true, :rounding => :down)
47
+ end
48
+
49
+ def test_sci_format
50
+ assert_equal '1.23E-3', DecNum('0.00123').to_s(format: :sci)
51
+ assert_equal '1.23E-6', DecNum('0.00000123').to_s(format: :sci)
52
+ assert_equal '1.23E-9', DecNum('0.00000000123').to_s(format: :sci)
53
+ assert_equal '1.23E-12', DecNum('0.00000000000123').to_s(format: :sci)
54
+ n = 1000
55
+ assert_equal "1.23E#{-n+2}", DecNum("123E-#{n}").to_s(format: :sci)
56
+ assert_equal "1.23E+#{n+2}", DecNum("123E#{n}").to_s(format: :sci)
57
+ end
58
+
59
+ def test_fix_format
60
+ assert_equal '0.00123', DecNum('0.00123').to_s(format: :fix)
61
+ assert_equal '0.00000123', DecNum('0.00000123').to_s(format: :fix)
62
+ assert_equal '0.00000000123', DecNum('0.00000000123').to_s(format: :fix)
63
+ assert_equal '0.00000000000123', DecNum('0.00000000000123').to_s(format: :fix)
64
+ n = 1000
65
+ assert_equal '0.'+'0'*(n-3)+'123', DecNum("123E-#{n}").to_s(format: :fix)
66
+ assert_equal '123'+'0'*n, DecNum("123E#{n}").to_s(format: :fix)
67
+ end
68
+
69
+ def test_auto_format
70
+ assert_equal '0.00123', DecNum('0.00123').to_s(format: :auto)
71
+ assert_equal '0.00000123', DecNum('0.00000123').to_s(format: :auto)
72
+ assert_equal '1.23E-7', DecNum('0.000000123').to_s(format: :auto)
73
+ assert_equal '1.23E-9', DecNum('0.00000000123').to_s(format: :auto)
74
+ assert_equal '1.23E-12', DecNum('0.00000000000123').to_s(format: :auto)
75
+ n = 1000
76
+ assert_equal "1.23E#{-n+2}", DecNum("123E-#{n}").to_s(format: :auto)
77
+ assert_equal "1.23E+#{n+2}", DecNum("123E#{n}").to_s(format: :auto)
78
+ end
79
+
80
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flt
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.4
4
+ version: 1.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Javier Goizueta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-03 00:00:00.000000000 Z
11
+ date: 2015-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -93,6 +93,7 @@ files:
93
93
  - test/test_epsilon.rb
94
94
  - test/test_exact.rb
95
95
  - test/test_flags.rb
96
+ - test/test_format.rb
96
97
  - test/test_formatter.rb
97
98
  - test/test_hex_format.rb
98
99
  - test/test_multithreading.rb
@@ -148,6 +149,7 @@ test_files:
148
149
  - test/test_epsilon.rb
149
150
  - test/test_exact.rb
150
151
  - test/test_flags.rb
152
+ - test/test_format.rb
151
153
  - test/test_formatter.rb
152
154
  - test/test_hex_format.rb
153
155
  - test/test_multithreading.rb