Synopsis¶ ↑
Radix
provides the means of converting to and from any base. For example, a number in base 256 can be represented by the array [100, 10] (ie. 100256 + 101) and easily converted to base 10.
[100,10].b(256).to_i #=> 25610
We can get an Array
representation as well.
[100,10].b(256).to_a(10) #=> [2,5,6,1,0] [100,10].b(256).to_a(62) #=> [6,41,4] [100,10].b(256).to_a(64) #=> [6,16,10]
To get a String
representation for any base use to_s.
[100,10].b(256).to_s(10) #=> "25610" [100,10].b(256).to_s(62) #=> "6 41 4" [100,10].b(256).to_s(64) #=> "6 16 10"
Notice that anything above base 10 is seperated by a space divider. The divider can be changed by providing a second argument.
[100,10].b(256).to_s(64, ':') #=> "6:16:10"
A string representation of a number can be converted upto base 62 (B62).
"10".b(62).to_s(10) #=> "62" "zz".b(62).to_s(10) #=> "3843"
To encode a number with a base greater than 10, use an Array
base. Radix
provides a built-in set of these, such as BASE::B62
.
[100,10].b(256).to_s(Radix::BASE::B62) #=> "6f4"
To use a custom character set, use an array of characters as the base rather than an integer. For example we can convert a base 10 number to another base 10 number but useing a different encoding.
base = %w[Q W E R T Y U I O U] "10".b(10).to_a(base) #=> ["W", "Q"] "10".b(10).to_s(base) #=> "WQ"
All of the above holds equally for floating point numbers.
Radix
Integer
¶ ↑
Radix
provides an Integer
class for working with integers in various bases.
require 'radix'
Initialization¶ ↑
Radix::Integer
‘s initializer can accept either an Integer
, String
or Array
as a value and an integer base.
Give an integer value, it will automatically be converted to the base specified.
check do |integer, base, digits| r = Radix::Integer.new(integer, base) r.digits.assert == digits end ok 8, 2, [1,0,0,0] ok 4, 2, [1,0,0] ok 8, 10, [8] ok 10, 10, [1, 0] ok 8, 16, [8] ok 16, 16, [1, 0]
Where as a String
value is taken to already be in the base given.
ok "1000", 2, [1,0,0,0] ok "100", 2, [1,0,0] ok "8", 10, [8] ok "10", 10, [1, 0] ok "8", 16, [8] ok "10", 16, [1, 0]
And an Array
is also taken to be in the base given.
ok %w[1 0 0 0], 2, [1,0,0,0] ok %w[ 1 0 0], 2, [1,0,0] ok %w[ 8], 10, [8] ok %w[1 0], 10, [1, 0] ok %w[ 8], 16, [8] ok %w[1 0], 16, [1, 0]
Integers can also be negative, rather than positive. In each case just prepend the value with a minus sign.
check do |integer, base, digits| r = Radix::Integer.new(integer, base) r.digits.assert == digits r.assert.negative? end ok -8, 2, ['-',1,0,0,0] ok "-1000", 2, ['-',1,0,0,0] ok %w[- 1 0 0 0], 2, ['-',1,0,0,0]
If a value has a digit outside of the range of the base an ArgumentError will be raised.
expect ArgumentError do Radix::Integer.new('9', 2) end
Radix
provides a convenience extension method to Integer
, String
and Array
called b, to more easily initialize a Radix
numeric object. The method simply passes the receiver on to Radix::Integer#new
.
check do |integer, base, digits| r = integer.b(base) r.assert.is_a?(Radix::Integer) r.digits.assert == digits end ok 8, 2, [1,0,0,0] ok 4, 2, [1,0,0] ok "1000", 2, [1,0,0,0] ok "100", 2, [1,0,0] ok %w"1 0 0 0", 2, [1,0,0,0] ok %w"1 0 0", 2, [1,0,0]
Conversion¶ ↑
Radix
integers can ve converted to other bases with the convert method.
b = "1000".b(2) d = b.convert(10) d.digits.assert == [8]
We can convert a Radix::Integer
to a regular base-10 Integer
with the to_i method.
b = "1000".b(2) d = b.to_i d.assert == 8
Equality¶ ↑
Radix
extend the Integer
, String
and Array
classes with the b method which simplifies the creation of Radix::Integer
instances. The following return the equivalent instance of Radix::Integer
.
a = 8.b(2) b = "1000".b(2) c = [1, 0, 0, 0].b(2) a.assert == b b.assert == c c.assert == a a.assert == 8 b.assert == 8 c.assert == 8
More stringent equality can be had from eql?, in which the other integer must be a Radix::Integer
too.
a.assert.eql?(b) a.refute.eql?(8)
Operations¶ ↑
Radix::Integer
supports all the usual mathematical operators.
Addition¶ ↑
check do |a, b, x| (a + b).assert == x end ok "1000".b(2), "0010".b(2), "1010".b(2) ok "1000".b(2), "2".b(8), "1010".b(2) ok "1000".b(2), "2".b(8), "10".b(10)
A more complex example.
x = "AZ42".b(62) + "54".b(10) x.assert == "2518124".b(10) x.assert == 2518124
Adding negative integers will, of course, be akin to subtraction.
ok "1000".b(2), "-0010".b(2), "110".b(2) ok "1000".b(2), "-2".b(8), "110".b(2) ok "1000".b(2), "-2".b(8), "6".b(10) ok "-1000".b(2), "0010".b(2), "-110".b(2) ok "-1000".b(2), "2".b(8), "-110".b(2) ok "-1000".b(2), "2".b(8), "-6".b(10) ok "-1000".b(2), "-0010".b(2), "-1010".b(2) ok "-1000".b(2), "-2".b(8), "-1010".b(2) ok "-1000".b(2), "-2".b(8), "-10".b(10)
Subtraction¶ ↑
check do |a, b, x| (a - b).assert == x end ok "1000".b(2), "10".b(2), "0110".b(2) ok "1000".b(2), "2".b(8), "0110".b(2) ok "1000".b(2), "2".b(8), "6".b(8) ok "1000".b(2), "2".b(8), "6".b(10)
A more complex example.
x = "AZ42".b(62) - "54".b(10) x.assert == "2518016".b(10) x.assert == 2518016
Multiplication¶ ↑
check do |a, b, x| (a * b).assert == x end ok "1000".b(2), "10".b(2), "10000".b(2) ok "1000".b(2), "2".b(8), "10000".b(2) ok "1000".b(2), "2".b(8), "20".b(8) ok "1000".b(2), "2".b(8), "16".b(10)
A more complex example.
x = "Z42".b(62) * "4".b(10) x.assert == "539160".b(10) x.assert == 539160
Division¶ ↑
check do |a, b, x| (a / b).assert == x end ok "1000".b(2), "10".b(2), "100".b(2) ok "1000".b(2), "2".b(8), "100".b(2) ok "1000".b(2), "2".b(8), "4".b(8) ok "1000".b(2), "2".b(8), "4".b(10)
A more complex example.
x = "AZ42".b(62) / "54".b(10) x.assert == "46630".b(10) x.assert == 46630
Power¶ ↑
check do |a, b, x| (a ** b).assert == x end ok "1000".b(2), "10".b(2), 64
Modulo¶ ↑
check do |a, b, x| (a % b).assert == x end ok "1000".b(2), "10".b(2), 0 ok "1000".b(2), "11".b(2), 2
Bitwise Shift¶ ↑
check do |a, b, x| (a << b).assert == x end ok "10".b(2), "10".b(2), "1000".b(2) ok "10".b(2), 2, "1000".b(2) ok "10".b(2), 2, 8
Bitwise AND¶ ↑
check do |a, b, x| (a & b).assert == x end ok "1010".b(2), "10".b(2), "10".b(2) ok "1010".b(2), "2".b(8), "10".b(2)
Coerce¶ ↑
When a Radix::Integer
is the operand in an operation against a regular Ruby Integer
, the calculation should still work via coerce.
check do |a, b, x| (a + b).assert == x end ok 10, "10".b(2), "12".b(10)
Radix
Float
¶ ↑
Radix
provides a Float
class for working with rational numbers in various bases. Actually Radix’s implementation of Float
is a fixed point, not a floating point.
require 'radix' D = Radix::DOT
Initialization¶ ↑
Radix::Float
‘s initializer can accept either an Integer
, Float
, String
or Array
as a value and an integer base.
Give a float value, it will automatically be converted to the base specified.
check do |float, base, digits| r = Radix::Float.new(float, base) r.digits.assert == digits end ok 8.5, 2, [1,0,0,0,D,1] ok 4.5, 2, [ 1,0,0,D,1] ok 8.1, 10, [ 8,D,1] ok 10.2, 10, [1,0,D,2] #ok 8.1, 16, [ 8,D,1] #ok 16.1, 16, [1,0,D,1]
Give an integer value, it will automatically be converted to the base specified and given a fraction part set to zero.
check do |float, base, digits| r = Radix::Float.new(float, base) r.digits.assert == digits end ok 8, 2, [1,0,0,0,D,0] ok 4, 2, [ 1,0,0,D,0] ok 8, 10, [ 8,D,0] ok 10, 10, [1,0,D,0] ok 8, 16, [ 8,D,0] ok 16, 16, [1,0,D,0]
Given a float, the same will occur.
ok 8.0, 2, [1,0,0,0,D,0] ok 4.0, 2, [ 1,0,0,D,0] ok 8.0, 10, [ 8,D,0] ok 10.0, 10, [1,0,D,0] ok 8.0, 16, [ 8,D,0] ok 16.0, 16, [1,0,D,0]
Where as a String
value is taken to already be in the base given.
ok "1000", 2, [1,0,0,0,D,0] ok "100", 2, [ 1,0,0,D,0] ok "8", 10, [ 8,D,0] ok "10", 10, [1,0,D,0] ok "8", 16, [ 8,D,0] ok "10", 16, [1,0,D,0] ok "1000.0", 2, [1,0,0,0,D,0] ok "100.0", 2, [ 1,0,0,D,0] ok "8.0", 10, [ 8,D,0] ok "10.0", 10, [1,0,D,0] ok "8.0", 16, [ 8,D,0] ok "10.0", 16, [1,0,D,0]
And an Array
is also taken to be in the base given.
ok %w[1 0 0 0], 2, [1,0,0,0,D,0] ok %w[ 1 0 0], 2, [ 1,0,0,D,0] ok %w[ 8], 10, [ 8,D,0] ok %w[1 0], 10, [1,0,D,0] ok %w[ 8], 16, [ 8,D,0] ok %w[1 0], 16, [1,0,D,0]
Passing in an Array
with a fraction part, either the DOT constant can be used, which is simply the symbol :‘.’, or the string ‘.’ can be used.
ok %w[1 0 0 0 . 0], 2, [1,0,0,0,D,0] ok %w[ 1 0 0 . 0], 2, [ 1,0,0,D,0] ok %w[ 8 . 0], 10, [ 8,D,0] ok %w[1 0 . 0], 10, [1,0,D,0] ok %w[ 8 . 0], 16, [ 8,D,0] ok %w[1 0 . 0], 16, [1,0,D,0]
Integers can also be negative, rather than positive. In each case just prepend the value with a minus sign.
check do |float, base, digits| r = Radix::Float.new(float, base) r.digits.assert = digits r.assert.negative? end ok( -8, 2, ['-',1,0,0,0,D,0]) ok( "-1000", 2, ['-',1,0,0,0,D,0]) ok( %w[- 1 0 0 0], 2, ['-',1,0,0,0,D,0])
If a value has a digit outside of the range of the base an ArgumentError will be raised.
expect ArgumentError do Radix::Float.new('9', 2) end
Radix
provides a convenience extension method to Integer
, String
and Array
called b, to more easily initialize a Radix
numeric object. The method simply passes the receiver on to Radix::Integer#new
.
check do |float, base, digits| r = float.b(base) r.assert.is_a?(Radix::Float) r.digits.assert = digits end ok 8.0, 2, [1,0,0,0,D,0] ok 4.0, 2, [ 1,0,0,D,0] ok "1000.0", 2, [1,0,0,0,D,0] ok "100.0", 2, [ 1,0,0,D,0] ok %w"1 0 0 0 . 0", 2, [1,0,0,0,D,0] ok %w"1 0 0 . 0", 2, [ 1,0,0,D,0]
Conversion¶ ↑
Radix
integers can ve converted to other bases with the convert method.
b = "1000.0".b(2) d = b.convert(10) d.digits.assert == [8,D,0]
We can convert a Radix::Float
to a regular base-10 Float
with the to_f method.
b = "1000.0".b(2) d = b.to_f d.assert == 8.0
We can convert a Radix::Float
to a regular base-10 Integer
with the to_i method.
b = "1000.0".b(2) d = b.to_i d.assert == 8
Equality¶ ↑
Radix
extend the Integer
, String
and Array
classes with the b method which simplifies the creation of Radix::Float
instances. The following return the equivalent instance of Radix::Float
.
a = 8.0.b(2) b = "1000.0".b(2) c = [1,0,0,0,'.',0].b(2) a.assert = b b.assert = c c.assert = a a.assert = 8.0 b.assert = 8.0 c.assert = 8.0
More stringent equality can be had from eql?, in which the other integer must be a Radix::Integer
too.
a.assert.eql?(b) a.refute.eql?(8.0)
Operations¶ ↑
Radix::Float
supports all the usual mathematical operators.
Addition¶ ↑
check do |a, b, x| (a + b).assert = x end ok "1000.0".b(2), "0010.0".b(2), "1010.0".b(2) ok "1000.0".b(2), "2.0".b(8), "1010.0".b(2) ok "1000.0".b(2), "2.0".b(8), "10.0".b(10)
A more complex example.
x = "AZ42.0".b(62) + "54.0".b(10) x.assert == "2518124.0".b(10) x.assert == 2518124.0
Adding negative integers will, of course, be akin to subtraction.
ok "1000.0".b(2), "-0010".b(2), "110.0".b(2) ok "1000.0".b(2), "-2".b(8), "110.0".b(2) ok "1000.0".b(2), "-2".b(8), "6.0".b(10) ok "-1000.0".b(2), "0010".b(2), "-110.0".b(2) ok "-1000.0".b(2), "2".b(8), "-110.0".b(2) ok "-1000.0".b(2), "2".b(8), "-6.0".b(10) ok "-1000.0".b(2), "-0010".b(2), "-1010.0".b(2) ok "-1000.0".b(2), "-2".b(8), "-1010.0".b(2) ok "-1000.0".b(2), "-2".b(8), "-10.0".b(10)
Subtraction¶ ↑
check do |a, b, x| (a - b).assert == x end ok "1000.0".b(2), "10".b(2), "110.0".b(2) ok "1000.0".b(2), "2".b(8), "110.0".b(2) ok "1000.0".b(2), "2".b(8), "6.0".b(8) ok "1000.0".b(2), "2".b(8), "6.0".b(10)
A more complex example.
x = "AZ42.0".b(62) - "54".b(10) x.assert == "2518016.0".b(10) x.assert == 2518016.0
Multiplication¶ ↑
check do |a, b, x| (a * b).assert = x end ok "1000.0".b(2), "10".b(2), "10000.0".b(2) ok "1000.0".b(2), "2".b(8), "10000.0".b(2) ok "1000.0".b(2), "2".b(8), "20.0".b(8) ok "1000.0".b(2), "2".b(8), "16.0".b(10)
A more complex example.
x = "Z42.0".b(62) * "4.0".b(10) x.assert == "539160.0".b(10) x.assert == 539160.0
Division¶ ↑
check do |a, b, x| (a / b).assert = x end ok "1000.0".b(2), "10".b(2), "100.0".b(2) ok "1000.0".b(2), "2".b(8), "100.0".b(2) ok "1000.0".b(2), "2".b(8), "4.0".b(8) ok "1000.0".b(2), "2".b(8), "4.0".b(10)
A more complex example.
x = "AZ40.0".b(62) / "62.0".b(10) x.assert == "40614.0".b(10) x.assert == 40614.0
Power¶ ↑
check do |a, b, x| (a ** b).assert == x end ok "1000.0".b(2), "10.0".b(2), 64.0
Modulo¶ ↑
check do |a, b, x| (a % b).assert == x end ok "1000.0".b(2), "10".b(2), 0 ok "1000.0".b(2), "11".b(2), 2
Coerce¶ ↑
When a Radix::Integer
is the operand in an operation against a regular Ruby Integer
, the calculation should still work via coerce.
check do |a, b, x| (a + b).assert == x end ok 10.0, "10".b(2), "12".b(10)
Radix
Rational¶ ↑
require 'radix'
Initialization¶ ↑
Radix::Rational
‘s initializer takes a numerator and a denominator, either of which can be an Integer
, Float
, String
or Array
along witha an integer base.
Give a integer value, it will automatically be converted to the base specified.
check do |num, dem, base, eqf| r = Radix::Rational.new(num, dem, base) r.assert == eqf end ok 1, 2, 2, 0.5 ok 1, 1, 2, 1.0 ok 8, 1, 10, 8.0 ok 8, 5, 10, 1.6 ok 8, 8, 10, 1.0 ok 10, 1, 10, 10.0 ok 10, 2, 10, 5.0 ok 10, 5, 10, 2.0 ok 8, 1, 16, 8.0 ok 16, 1, 16, 16.0
Reduction¶ ↑
check do |a, x| r = a.reduce r.assert == x end ok [10,5].br(10), [2,1].br(10) ok [30,3].br(10), [10,1].br(10)
Operations¶ ↑
Addition¶ ↑
check do |a, b, x| r = a + b r.assert == x end ok [8,5].br(10), [1,2].br(10), [21,10].br(10) ok [8,5].br(10), 1, [13,5].br(10) ok [8,5].br(10), 0.5, [21,10].br(10)
Subtraction¶ ↑
check do |a, b, x| r = a - b r.assert == x end ok [8,5].br(10), [1,2].br(10), [11,10].br(10)
Multiplication¶ ↑
check do |a, b, x| r = a * b r.assert == x end ok [8,5].br(10), [1,2].br(10), [8,10].br(10)
Division¶ ↑
check do |a, b, x| r = a / b r.assert == x end ok [8,5].br(10), [1,2].br(10), [16,5].br(10)
Radix::Base
¶ ↑
The Radix::Base
class is an encapsulatin of a numeric base. By creating an instance of Base one can convert numbers to and from other bases.
require 'radix/base'
Base Instance¶ ↑
First let’s try something we all know, converting decimal to hexideciaml. To do this we setup the radix base objects for each base.
b10 = Radix::Base.new(Radix::BASE::B10) b16 = Radix::Base.new(Radix::BASE::B16)
Now we can covert from one base to the other.
b16.convert("16" , b10).should == "10" b16.convert("160", b10).should == "A0" b16.convert("255", b10).should == "FF"
To confirm, lets convert from hexidecimal back to decimal.
b10.convert("10", b16).should == "16" b10.convert("A0", b16).should == "160" b10.convert("FF", b16).should == "255"
If we are happy with standard encodings then we can simply provide an integer base, rather than a Radix::Base
object.
b10.convert("10", 16).should == "16" b10.convert("A0", 16).should == "160" b10.convert("FF", 16).should == "255"
Now let’s try a more down to earth base, my favorite, senary, or base six.
b6 = Radix::Base.new(0..5) b6.convert("39", 10).should == "103"
And the notations need not be in ASCII order. Odd alternate notations can be used as well.
b10 = Radix::Base.new([:Q, :W, :E, :R, :T, :Y, :U, :I, :O, :U]) b10.convert("FF", 16) #=> "EYY"
Encoding and Decoding¶ ↑
Radix::Base
instances can also be used to encode and decode strings.
b16.encode("CHARLIE").should == "434841524C4945" b16.decode("434841524C4945").should == "CHARLIE"
Module Methods¶ ↑
For further convenience, Radix::base provides functions to convert to and from standard notations upto 62 without creating an instance of Radix::Base
.
Radix.convert("10", 16, 10).should == "16" Radix.convert("A0", 16, 10).should == "160" Radix.convert("FF", 16, 10).should == "255"
Let’s try that again with the maximum base supported.
Radix.convert( "62", 10, 62).should == "10" Radix.convert("8814542", 10, 62).should == "az42" Radix.convert( "10", 62, 10).should == "62" Radix.convert( "az42", 62, 10).should == "8814542"
Finally, we will demonstrate how to convert bases larger than 62. These can only be represented as arrays since there are not enough latin characters to represent them.
Radix.convert_base([100, 10], 256, 10).should == [2, 5, 6, 1, 0] Radix.convert_base([2, 5, 6, 1, 0], 10, 256).should == [100, 10] Radix.convert_base([1, 0, 1, 0, 1], 2, 10).should == [2, 1]
Zero becomes empty string (#4)¶ ↑
Example of the issue:
0.b(10).to_s #=> ""
I would expect “0” as a result.
0.b(10).to_s #=> "0"
Okay, lets make sure this works for Floats.
0.0.b(10).to_s #=> "0.0"
And Rationals too.
[0,1].br(10).to_s #=> "0/1"