flt 1.4.4 → 1.4.5

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