Why does the FixNum#to_s method in in Ruby only accept radixes from 2 to 36?

StackOverflow https://stackoverflow.com/questions/9827498

  •  25-05-2021
  •  | 
  •  

Вопрос

I looked at the documentation and even peeked at the C source, and I can't see why they limited the accepted radixes to 2..36. Anybody know?

Это было полезно?

Решение

As others have pointed out, radix < 2 is troublesome to render. and there's no conventional agreement on what characters to use for radixes larger than ['0'..'9'] + ['a'..'z'], which is why the standard method doesn't support radix outside those limits.

If you really want a custom radix representation, you would need to define the alphabet of symbols to use for the digits. Here's a little module that will give you the capability.

module CustomRadix
  # generate string representation of integer, using digits from custom alphabet
  # [val] a value which can be cast to integer
  # [digits] a string or array of strings representing the custom digits
  def self.custom_radix val, digits

    digits = digits.to_a unless digits.respond_to? :[]
    radix = digits.length
    raise ArgumentError, "radix must have at least two digits" if radix < 2

    i = val.to_i
    out = []
    begin
      rem = i % radix
      i /= radix
      out << digits[rem..rem]
    end until i == 0

    out.reverse.join
  end

  # can be used as mixin, eg class Integer; include CustomRadix; end
  # 32.custom_radix('abcd') => "caa" (200 base 4) equiv to 32.to_s(4).tr('0123','abcd')
  def custom_radix digits
    CustomRadix.custom_radix self, digits
  end
end

example use:

$ irb
>> require '~/custom_radix'
=> true
>> CustomRadix.custom_radix(12345,'0'..'9')
=> "12345"
>> CustomRadix.custom_radix(12345,'.-')
=> "--......---..-"
>> funny_hex_digits = ('0'..'9').to_a + ('u'..'z').to_a
=> ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "u", "v", "w", "x", "y", "z"]
>> CustomRadix.custom_radix(255, funny_hex_digits)
=> "zz"
>> class Integer; include CustomRadix; end
=> Integer
>> (2**63).custom_radix(funny_hex_digits)
=> "8000000000000000"
>> (2**64+2**63+2**62).custom_radix(funny_hex_digits)
=> "1w000000000000000"
>> base64_digits = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a << '+' << '/'
=> ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"]
>> 123456.custom_radix(base64_digits)
=> "eJA"

Другие советы

I don't know anything about ruby, but I know there are 10 decimal digits plus 26 alpha digits. that's 36.

How would you render a number in base 1? How would you render a number in base 37? In base 300?

It's conventional to use 0..9 and A..F for hexadecimal numbers. It's intuitive to continue using the alphabet for higher bases, but that only gets you to 36. As there are few uses (if any - I've never seen one) of higher bases, there's no convention for anything beyond that. Except perhaps for base 64, which is a quite different beast, specific to a single base, and not terribly old either. Also, there are a gazillion incompatible variants, which only reinforced my point.

And as for base 1: Unary counting exists, but it's not terribly useful, even less common in computing, and very easy to emulate (just concat n times the same character). Besides, people probably have vastly different opinions on what that character should be.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top