预期为整数的不需要的浮点数
Unwanted float expected to be integer
我正在尝试解决一个问题:
Your task is to write a simple function that takes a number of meters,
and outputs it using metric prefixes.For this exercise we just want
units bigger than a meter, from meters up to yottameters, excluding
decameters and hectometers.All values passed in will be positive
integers
Examples
meters(51500)
# returns "51.5km"
meters(5000000)
# returns "5Mm"
我的代码:
def meters(x)
map_prefix={ 24=>'Y', 21=> 'Z', 18=> 'E', 15=> 'P', 12=> 'T', 9=>'G', 6=>'M', 3=>'k',0=>'' }
digits=(x.to_i.to_s.size-1)/3
division=x/(10.0**(3*digits))
"#{division}#{map_prefix[3*digits]}m".sub(/\.0([^\d])/,'')
end
它不适用于 meters(56*10**24) #->expected 56Ym ,instead got 56.000000000004Ym
,但它适用于更大的数字,例如 meters(88*10**24) #->88Ym
。该代码通过了 50 次测试中的 49 次,有人可以帮我找出错误吗?
我认为你的问题是你乘以 10.0
,但你只想处理整数。
像下面这样的东西就是你想要的。 (我也在做一些样式更改)。
def meters(x)
digits=(x.to_i.to_s.size-1)/3
prefix = prefixes[3*digits]
value = x / (10 ** (3 * digits))
"#{value}#{prefix}m".sub(/\.0([^\d])/,'')
end
def prefixes
{
24 => 'Y',
21 => 'Z',
18 => 'E',
15 => 'P',
12 => 'T',
9 => 'G',
6 => 'M',
3 => 'k',
0 => ''
}
end
这至少给了错误的解决方案。我不保证它是所有问题的正确解决方案。
我在这里将散列放入它自己的函数中,因为它看起来像是静态的。我在评论中提到的其他事情也是如此。
您可以使用 Float#round
将数字四舍五入到特定数字。对于这个问题,3
应该没问题。
"#{division.round(3)}#{map_prefix[3*digits]}m".sub(/\.0([^\d])/,'')
# ^^^^^^^^^
问题背后的原因是:Float
可以存储非常大的整数。但是,对于大于某个限制的整数,Float
不能 精确地存储它们 。对于 [IEEE-754 双精度] 浮点数,该限制为 253.
破解代码以使其正常工作的最简单方法似乎是避免使用浮点数,如下所示:
#!/usr/bin/env ruby
def meters(x)
map_prefix={ 24=>'Y', 21=> 'Z', 18=> 'E', 15=> 'P', 12=> 'T', 9=>'G', 6=>'M', 3=>'k',0$
map_prefix.default = 'Y'
digits = [((x.to_s.size-1)/3)*3, 24].min
division = x.to_s.insert(-digits - 1, '.')
division.sub!(/0+\z/, '')
division.sub!(/\.\z/, '')
"#{division}#{map_prefix[digits]}m"
end
puts meters(51500)
puts meters(5000000)
puts meters(5001)
puts meters(88*10**24)
puts meters(88*10**24 + 1)
puts meters(100)
puts meters(88*10**27)
puts meters(88*10**27 + 1)
结果如下:
./ruby.rb
51.5km
5Mm
5.001km
88Ym
88.000000000000000000000001Ym
100m
88000Ym
88000.000000000000000000000001Ym
更严重的是,您需要避免任何字符串(根本不应转换为字符串)。
你需要任意精度,所以 float 根本不是一个选项。
FWIW 这一行会将 ruby 的鸭子输入更改为浮动。 (请注意,您将 10.0 作为浮点数引入。)
division=x/(10.0**(3*digits))
处理大数时,最好使用内置的BigDecimal class。更清晰,更不容易出错,尽管这绝对不是防错代码。
require 'bigdecimal'
def meters(x)
b = BigDecimal.new(x).split
"#{b[1]}#{prefix[b[3] - b[1].length]}m"
end
def prefix
{
24 =>'Y', 21 => 'Z', 18 => 'E', 15 => 'P',
12 => 'T', 9 =>'G', 6 =>'M', 3 =>'k',0 =>''
}
end
UNITS = " kMGTPEZY"
def meters(x)
sx = x.to_s
pwr = sx.size - 1
return sx if pwr < 3
pfx_sz = (pwr < 24) ? (1 + pwr % 3) : pwr - 23
sxs = sx.reverse.to_i.to_s.reverse
sxs = sxs.ljust([sxs.size, pfx_sz].max, '0')
pfx = sxs[0, pfx_sz]
pfx << '.' if (pfx.size < sxs.size)
"#{ pfx }#{ sxs[pfx_sz..-1] }#{ UNITS[[pwr/3, 8].min] }"
end
meters 3 #=> "3"
meters 100 #=> "100"
meters 4000 #=> "4k"
meters 5001 #=> "5.001k"
meters 51500 #=> "51.5k"
meters 5000000 #=> "5M"
meters 88*10**24 #=> "88Y"
meters 88*10**24 + 1 #=> "88.000000000000000000000001Y"
meters 88*10**27 #=> "88000Y"
meters 88*10**27 + 1 #=> "88000.000000000000000000000001Y"
我正在尝试解决一个问题:
Your task is to write a simple function that takes a number of meters, and outputs it using metric prefixes.For this exercise we just want units bigger than a meter, from meters up to yottameters, excluding decameters and hectometers.All values passed in will be positive integers Examples
meters(51500)
# returns "51.5km"
meters(5000000)
# returns "5Mm"
我的代码:
def meters(x)
map_prefix={ 24=>'Y', 21=> 'Z', 18=> 'E', 15=> 'P', 12=> 'T', 9=>'G', 6=>'M', 3=>'k',0=>'' }
digits=(x.to_i.to_s.size-1)/3
division=x/(10.0**(3*digits))
"#{division}#{map_prefix[3*digits]}m".sub(/\.0([^\d])/,'')
end
它不适用于 meters(56*10**24) #->expected 56Ym ,instead got 56.000000000004Ym
,但它适用于更大的数字,例如 meters(88*10**24) #->88Ym
。该代码通过了 50 次测试中的 49 次,有人可以帮我找出错误吗?
我认为你的问题是你乘以 10.0
,但你只想处理整数。
像下面这样的东西就是你想要的。 (我也在做一些样式更改)。
def meters(x)
digits=(x.to_i.to_s.size-1)/3
prefix = prefixes[3*digits]
value = x / (10 ** (3 * digits))
"#{value}#{prefix}m".sub(/\.0([^\d])/,'')
end
def prefixes
{
24 => 'Y',
21 => 'Z',
18 => 'E',
15 => 'P',
12 => 'T',
9 => 'G',
6 => 'M',
3 => 'k',
0 => ''
}
end
这至少给了错误的解决方案。我不保证它是所有问题的正确解决方案。
我在这里将散列放入它自己的函数中,因为它看起来像是静态的。我在评论中提到的其他事情也是如此。
您可以使用 Float#round
将数字四舍五入到特定数字。对于这个问题,3
应该没问题。
"#{division.round(3)}#{map_prefix[3*digits]}m".sub(/\.0([^\d])/,'')
# ^^^^^^^^^
问题背后的原因是:Float
可以存储非常大的整数。但是,对于大于某个限制的整数,Float
不能 精确地存储它们 。对于 [IEEE-754 双精度] 浮点数,该限制为 253.
破解代码以使其正常工作的最简单方法似乎是避免使用浮点数,如下所示:
#!/usr/bin/env ruby
def meters(x)
map_prefix={ 24=>'Y', 21=> 'Z', 18=> 'E', 15=> 'P', 12=> 'T', 9=>'G', 6=>'M', 3=>'k',0$
map_prefix.default = 'Y'
digits = [((x.to_s.size-1)/3)*3, 24].min
division = x.to_s.insert(-digits - 1, '.')
division.sub!(/0+\z/, '')
division.sub!(/\.\z/, '')
"#{division}#{map_prefix[digits]}m"
end
puts meters(51500)
puts meters(5000000)
puts meters(5001)
puts meters(88*10**24)
puts meters(88*10**24 + 1)
puts meters(100)
puts meters(88*10**27)
puts meters(88*10**27 + 1)
结果如下:
./ruby.rb
51.5km
5Mm
5.001km
88Ym
88.000000000000000000000001Ym
100m
88000Ym
88000.000000000000000000000001Ym
更严重的是,您需要避免任何字符串(根本不应转换为字符串)。 你需要任意精度,所以 float 根本不是一个选项。
FWIW 这一行会将 ruby 的鸭子输入更改为浮动。 (请注意,您将 10.0 作为浮点数引入。)
division=x/(10.0**(3*digits))
处理大数时,最好使用内置的BigDecimal class。更清晰,更不容易出错,尽管这绝对不是防错代码。
require 'bigdecimal'
def meters(x)
b = BigDecimal.new(x).split
"#{b[1]}#{prefix[b[3] - b[1].length]}m"
end
def prefix
{
24 =>'Y', 21 => 'Z', 18 => 'E', 15 => 'P',
12 => 'T', 9 =>'G', 6 =>'M', 3 =>'k',0 =>''
}
end
UNITS = " kMGTPEZY"
def meters(x)
sx = x.to_s
pwr = sx.size - 1
return sx if pwr < 3
pfx_sz = (pwr < 24) ? (1 + pwr % 3) : pwr - 23
sxs = sx.reverse.to_i.to_s.reverse
sxs = sxs.ljust([sxs.size, pfx_sz].max, '0')
pfx = sxs[0, pfx_sz]
pfx << '.' if (pfx.size < sxs.size)
"#{ pfx }#{ sxs[pfx_sz..-1] }#{ UNITS[[pwr/3, 8].min] }"
end
meters 3 #=> "3"
meters 100 #=> "100"
meters 4000 #=> "4k"
meters 5001 #=> "5.001k"
meters 51500 #=> "51.5k"
meters 5000000 #=> "5M"
meters 88*10**24 #=> "88Y"
meters 88*10**24 + 1 #=> "88.000000000000000000000001Y"
meters 88*10**27 #=> "88000Y"
meters 88*10**27 + 1 #=> "88000.000000000000000000000001Y"