2015-08-21 3 views
0

Я пытаюсь решить проблему:Нежелательные поплавок ожидается целое

Ваша задача состоит в том, чтобы написать простую функцию, которая принимает число метров, и выводит его с помощью метрики prefixes.For это упражнение мы просто хотим единиц больше, чем на метре, от нескольких метров до yottameters, за исключением дкх и значений hectometers.All передаются в будет положительным целыми Пример

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])/,'\1') 
end 

Это не работает для meters(56*10**24) #->expected 56Ym ,instead got 56.000000000004Ym, но это работает для больших чисел, таких как meters(88*10**24) #->88Ym. Код проходит 49 из 50 тестов, может ли кто-нибудь помочь мне найти ошибку?

+0

Два стилистические комментарии. В этом случае вам не нужно использовать 'return'. В Ruby последнее оцениваемое значение подразумевается 'return'ed. Во-вторых, не делайте математику ('x/(10.0 ...') внутри строки. Уродливо и немного сложно следовать. Нет причин для того, чтобы вы не разбивали ее на разные переменные и не создавали свою строку из разных частей. –

+0

Каков ответ, который вы получаете, и какой ответ вы ожидаете от неудачного ввода? –

+0

@JustinWood Спасибо за исправления стиля и быстрый ответ, должен ли я исправить это в сообщении? И я также добавил ожидаемый результат и тот, который я получил вместо этого, забыл добавить информацию. –

ответ

0

Я думаю, что ваша проблема заключается в том, что вы умножаетесь на 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])/,'\1') 
end 

def prefixes 
    { 
    24 => 'Y', 
    21 => 'Z', 
    18 => 'E', 
    15 => 'P', 
    12 => 'T', 
    9 => 'G', 
    6 => 'M', 
    3 => 'k', 
    0 => '' 
    } 
end 

Это, по крайней мере, дает правильное решение по неправильному. Я не собираюсь гарантировать, что это правильное решение всего.

Я сделал хэш в своей функции здесь, потому что кажется, что он будет статичным. Также были другие вещи, о которых я упоминал в своем комментарии.

+0

Некоторые из результатов имеют с плавающей запятой 'метров (51500); // возвращает« 51.5km »'. –

+0

В таком случае вы бы необходимо написать функцию, которая может вычислять значащие цифры. –

0

Вы можете использовать Float#round, чтобы округлить число до определенных цифр. Для этой определенной проблемы 3 должен преуспеть.

"#{division.round(3)}#{map_prefix[3*digits]}m".sub(/\.0([^\d])/,'\1') 
#   ^^^^^^^^^ 

Причиной этой проблемы является: Float может хранить целые числа, что довольно большой. Однако, для целых чисел, превышающих определенный предел, Float не может сохранить их точно. Для плавающей запятой [IEEE-754 с двойной точностью] этот предел равен 2 .

+0

Спасибо. Это решило проблему. –

1

Самый простой способ взломать ваш код, чтобы заставить его работать, кажется, чтобы избежать флоат-указывая номер, как здесь:

#!/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 

серьезно, что вам нужно избегайте струн вообще (никаких преобразований в строку вообще не должно быть сделано). Вам нужна произвольная точность, поэтому поплавок не является вариантом.

0

FWIW Эта линия изменит утиную рубин, чтобы наплыть. (Обратите внимание, вы вводите 10,0 как поплавок.)

division=x/(10.0**(3*digits)) 

Когда имеешь дело с большими числами, его лучше использовать встроенный в BigDecimal классе.Гораздо чище и менее подвержено ошибкам, хотя это, безусловно, НЕ код ошибки.

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 
+0

Но этот код не соответствует одному из примеров 'метров (51500) #yields 515m' –

0
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"