2012-12-22 85 views
7

在我正在寫的腳本中,我想在Ruby中找到Fixnum的長度。我可以做<num>.to_s.length,但是有什麼方法可以直接找到Fixnum的長度而不必將其轉換爲字符串?如何確定Ruby中Fixnum的長度?

+0

什麼是「Fixnum」的長度?在什麼表示? –

+0

@JörgWMittag:它有多少位數。 – Orcris

回答

23
puts Math.log10(1234).to_i + 1 # => 4 

你可以將它添加到Fixnum對象是這樣的:

class Fixnum 
    def num_digits 
    Math.log10(self).to_i + 1 
    end 
end 

puts 1234.num_digits # => 4 
+11

每次我介紹一些內容時,我都會感到驚喜。在MRI 1.9.3中,對於由Fixnum表示的任何整數,「n.to_s.length」更快。更快的_lot_:在我的盒子裏,'n.to_s.length'取決於對數方法的三分之一到一半的時間,取決於數字的長度。如果該數字必須表示爲一個Bignum,則對數方法開始獲勝。儘管這兩種方法的速度都非常快,約爲0.6毫秒(對數方法),0.2到0.3毫秒(對於字符串方法)。 –

+0

@WayneConrad:聽起來像'Math.log10'必須有一個相當低效的實現。我只是嘗試了一種簡單的方法,它遍歷所有10位的適合32/64位的表格,並對每一個進行比較 - 它比「Math.log10」更快,但仍比'to_s'慢。它可以通過「展開」同一個表的二進制搜索而變得更快,就像展開循環一樣(然後不再需要表 - 相同的數字將被硬編碼爲一系列條件)。 –

+4

小心。這會導致非正數的錯誤。 – sawa

0

如果你不想使用正則表達式,你可以使用這個方法:

def self.is_number(string_to_test) 
is_number = false 
# use to_f to handle float value and to_i for int 
string_to_compare = string_to_test.to_i.to_s 
string_to_compare_handle_end = string_to_test.to_i 

# string has to be the same 
if(string_to_compare == string_to_test) 
    is_number = true 
end 
# length for fixnum in ruby 
size = Math.log10(string_to_compare_handle_end).to_i + 1 
# size has to be the same 
if(size != string_to_test.length) 
    is_number = false 
end 
is_number 
end 
1

另一種方式:

def ndigits(n) 
    n=n.abs 
    (1..1.0/0).each { |i| return i if (n /= 10).zero? } 
end 

ndigits(1234) # => 4 
ndigits(0) # => 1 
ndigits(-123) # => 3 
4

儘管頂級投票循環很好,它不是很Ruby,而且對於大數量來說會很慢,.to_s是一個內置函數,因此速度會更快。幾乎普遍內置的函數將比構造循環或迭代器快得多。

5

Ruby 2.4有一個Integer#digits方法,它返回一個包含數字的數組。

num = 123456 
num.digits 
# => [6, 5, 4, 3, 2, 1] 
num.digits.count 
# => 6 

編輯:

要處理負數(感謝@MatzFan),使用絕對值。 Integer#abs

-123456.abs.digits 
# => [6, 5, 4, 3, 2, 1] 
+0

..如果它是一個正整數,否則爲'Math :: DomainError'。儘管如此,更多的Ruby – MatzFan

0

旁註爲紅寶石2.4 +

我跑了不同的解決方案的一些基準,並Math.log10(x).to_i + 1實際上是快了很多x.to_s.lengthcomment from @Wayne Conrad已過時。 new solution with digits.count遠遠落在後面,尤其是對於更大的數字:

with_10_digits = 2_040_240_420 

print Benchmark.measure { 1_000_000.times { Math.log10(with_10_digits).to_i + 1 } } 
# => 0.100000 0.000000 0.100000 ( 0.109846) 
print Benchmark.measure { 1_000_000.times { with_10_digits.to_s.length } } 
# => 0.360000 0.000000 0.360000 ( 0.362604) 
print Benchmark.measure { 1_000_000.times { with_10_digits.digits.count } } 
# => 0.690000 0.020000 0.710000 ( 0.717554) 

with_42_digits = 750_325_442_042_020_572_057_420_745_037_450_237_570_322 

print Benchmark.measure { 1_000_000.times { Math.log10(with_42_digits).to_i + 1 } } 
# => 0.140000 0.000000 0.140000 ( 0.142757) 
print Benchmark.measure { 1_000_000.times { with_42_digits.to_s.length } } 
# => 1.180000 0.000000 1.180000 ( 1.186603) 
print Benchmark.measure { 1_000_000.times { with_42_digits.digits.count } } 
# => 8.480000 0.040000 8.520000 ( 8.577174)