我有一个表单,用户输入一个十进制值,下拉四个选项:Quarter (.00, .25, .50, .75)
,Dime (.10, .20, .30 .. .90)
,Penny (.01, .02, .03 ... .99)
和UP
。此外,您还可以选择轮次DOWN
或Float
。
这些选项用于舍入用户输入的值。我修补了round_to_quarter
课程,并添加了class Float
def round_to_quarter
(self * 4).round / 4.0
end
def round_to_dime
#TODO
end
def round_to_penny
#TODO
end
def round_to_dollar
#TODO
end
end
9.22.round_to_quarter #=> 9.25
正常工作:
func setupClient(){
let configuration = ConfigData.sharedInstance
if (configuration.sipLogin == SipLoginStatus.SipLoginStatusLoggedOut && configuration.sipUsername?.length == 0) && (configuration.acsLogin == ACSLoginStatus.ACSLoginStatusLoggedOut && configuration.acsUsername?.length == 0){
return
}
//the app is broken here with the code "exc_bad_access(code=1,address=0x20)" and CSClient is a Class imported by a third party framework.
CSClient.setLogLevel(CSLogLevel.Debug)
...
}
如何舍入Dime(.10,.20,.30 .. .90)和Penny(.01,。02,。03 ... .99)选项的值并向上和向下舍入?< / p>
Ruby版本是2.2.3
答案 0 :(得分:4)
这是以任何精度执行此操作的通用方法:
class Float
def round_currency(precision: 1, direction: :none)
round_method = case direction
when :none then :round
when :up then :ceil
when :down then :floor
end
integer_value = (self * 100).round
((integer_value / precision.to_f).send(round_method) * precision / 100.0)
end
end
# USAGE
9.37.round_currency(direction: :none, precision: 10)
# => 9.4
9.37.round_currency(direction: :up, precision: 25)
# => 9.5
9.37.round_currency(direction: :none)
# => 9.37
# Precision is defined in pennies: 10 dime, 25 quarter, 100 dollar. 1 penny is default
此代码首先将float转换为整数以确保准确性。请谨慎使用ceil
和floor
进行浮动数字运算 - 由于准确性错误,您可能会得到奇怪的结果,例如: 9.37 * 100 = 936.9999999999999
。如果你floor
结果,那么你最终将四舍五入为9.36
答案 1 :(得分:0)
我认为您可以尝试以下覆盖...
Ceil选择UP,Floor选择DOWN
class Float
def ceil_to_quarter
(self * 4).ceil / 4.0
end
def floor_to_quarter
(self * 4).floor / 4.0
end
def ceil_to_dime
(self * 10).ceil / 10.0
end
def floor_to_dime
(self * 10).floor / 10.0
end
def ceil_to_penny
(self * 10).ceil / 10.0
end
def floor_to_penny
(self * 100).floor / 100.0
end
end
答案 2 :(得分:0)
圆到便士应该像季度一样正常工作
def round_to_penny
((self * 100).round/100.0)
end
然而,由于您要舍入到小数点后1位,因此舍入到对角线将减少到小数点后1位。 显示值时,您可以将其更改为2位小数。
def round_to_dime
((self * 10).round/10.0)
end
您可以使用&#39;%。2f&#39;但是:
'%.2f' % 9.25.round_to_dime => "9.30"
答案 3 :(得分:0)
处理这种情况的另一种方法:
require 'bigdecimal'
class Rounder
DENOMS = {penny: 0.01, nickel: 0.05, dime: 0.1, quarter: 0.25, half_dollar: 0.5, dollar: 1.0}
DENOMS.each do |denom,val|
define_method("round_to_#{denom}") do |direction: :nearest|
self.send(direction, self.send(:step_def, val))
end
end
def initialize(v)
@v = BigDecimal(v.to_s)
@enum_range = (@v.floor..@v.floor + 1)
end
def round_to(denom,direction: :nearest)
check_denom(denom)
if denom.is_a?(Numeric)
self.send(direction, self.send(:step_def, denom))
else
self.public_send("round_to_#{denom}",direction: direction)
end
end
private
def down(enum)
enum.reverse_each.detect {|f| f <= @v }
end
def up(enum)
enum.detect {|f| f >= @v }
end
def nearest(enum)
[up(enum),down(enum)].min_by {|n| (n - @v).abs}
end
def step_def(val)
@enum_range.step(val)
end
def check_denom(denom)
if denom.is_a?(Numeric)
raise ArgumentError, "Numeric denom must be greater than 0 and less than or equal to 1" if (denom > 1 || denom <= 0)
elsif denom.respond_to?(:to_sym)
raise ArgumentError, "expecting one of #{DENOMS.keys} got :#{denom.to_sym}" unless DENOMS.keys.include?(denom.to_sym)
else
raise ArgumentError,"expected Numeric, Symbol or String got #{denom.class}"
end
end
end
这允许灵活地实现预定义的面额以及舍入到任何所需的精度。显然,通过缩小@enum_range
可以对这一点进行优化以获得更长的精度。
您可以将其修补到Numeric
以允许直接访问:
class Numeric
def round_to(denom,direction: :nearest)
Rounder.new(self).round_to(denom,direction: direction)
end
end
然后使用
r = Rounder.new(9.22)
r.round_to_quarter
#=> 9.25
r.round_to_dime(direction: :up)
#=> 9.3
r.round_to(:nickel)
#=> 9.2
r.round_to(0.45, direction: :up)
#=> 9.45
r.round_to({})
#=> ArgumentError: expected Numeric, Symbol or String got Hash
r.round_to(:pound)
#=> ArgumentError: expecting one of [:penny, :nickel, :dime, :quarter,
# :half_dollar, :dollar] got :pound
77.43.round_to(:quarter)
#=> 77.5
Rounder.new("123.0000001").round_to_half_dollar(direction: :up)
#=> 123.5
#Obviously a Fixnum is already precise but it does still work
[:down,:up].each do |dir|
puts "#{dir} => #{12.round_to(:quarter, direction: dir)}"
end
# down => 12.0
# up => 12.0