# Radix Float

Radix provides a Float class for working with rational numbers in various bases.
Actually Radix's implementation of Float is a <i>fixed point</i>, 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)