aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
diff options
context:
space:
mode:
authorKenta Murata & Akira Matsuda <mrkn@cookpad.com>2013-12-20 15:35:13 +0900
committerAkira Matsuda <ronnie@dio.jp>2013-12-20 16:26:35 +0900
commit9e997e9039435617b6a844158f5437e97f6bc107 (patch)
tree2d1e8853e3ac9b5e45fc5e06ad3ce667e6675401 /activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
parentc437a98acaf759d53a85151947709f5efe499a27 (diff)
downloadrails-9e997e9039435617b6a844158f5437e97f6bc107.tar.gz
rails-9e997e9039435617b6a844158f5437e97f6bc107.tar.bz2
rails-9e997e9039435617b6a844158f5437e97f6bc107.zip
Fix AS::NumberHelper results with large precisions
before: ActiveSupport::NumberHelper.number_to_rounded '3.14159', precision: 50 => "3.14158999999999988261834005243144929409027099609375" after: ActiveSupport::NumberHelper.number_to_rounded '3.14159', precision: 50 => "3.14159000000000000000000000000000000000000000000000"
Diffstat (limited to 'activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb')
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb44
1 files changed, 37 insertions, 7 deletions
diff --git a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
index 273667fdae..c42354fc83 100644
--- a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
@@ -5,28 +5,50 @@ module ActiveSupport
self.validate_float = true
def convert
- @number = Float(number)
-
precision = options.delete :precision
significant = options.delete :significant
+ case number
+ when Float, String
+ @number = BigDecimal(number.to_s)
+ when Rational
+ if significant
+ @number = BigDecimal(number, digit_count(number.to_i) + precision)
+ else
+ @number = BigDecimal(number, precision)
+ end
+ else
+ @number = number.to_d
+ end
+
if significant && precision > 0
digits, rounded_number = digits_and_rounded_number(precision)
precision -= digits
precision = 0 if precision < 0 # don't let it be negative
else
- rounded_number = BigDecimal.new(number.to_s).round(precision).to_f
+ rounded_number = number.round(precision)
+ rounded_number = rounded_number.to_i if precision == 0
rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
end
- delimited_number = NumberToDelimitedConverter.convert("%01.#{precision}f" % rounded_number, options)
+ formatted_string =
+ case rounded_number
+ when BigDecimal
+ s = rounded_number.to_s('F') + '0'*precision
+ a, b = s.split('.', 2)
+ a + '.' + b[0, precision]
+ else
+ "%01.#{precision}f" % rounded_number
+ end
+
+ delimited_number = NumberToDelimitedConverter.convert(formatted_string, options)
format_number(delimited_number)
end
private
def digits_and_rounded_number(precision)
- if number.zero?
+ if zero?
[1, 0]
else
digits = digit_count(number)
@@ -38,11 +60,11 @@ module ActiveSupport
end
def calculate_rounded_number(multiplier)
- (BigDecimal.new(number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier
+ (number / BigDecimal.new(multiplier.to_f.to_s)).round * multiplier
end
def digit_count(number)
- (Math.log10(number.abs) + 1).floor
+ (Math.log10(absolute_number(number)) + 1).floor
end
def strip_insignificant_zeros
@@ -57,6 +79,14 @@ module ActiveSupport
number
end
end
+
+ def absolute_number(number)
+ number.respond_to?(:abs) ? number.abs : number.to_d.abs
+ end
+
+ def zero?
+ number.respond_to?(:zero?) ? number.zero? : number.to_d.zero?
+ end
end
end
end