# 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)