class Numerals::Format::BaseScaler

This converts the number representation contained in an ExpSetter scaling the base of the significand.

This is typically used when the ExpSetter base is 2 to render the number in C99 '%A' format, i.e., in hexadecimal base. Only the significand is shown in base 16; the exponent is still a power of two, and represented in base 10.

This is a generalization of the %A format where any base which is a power of the original base can be used for the significand.

The number exponent is previously adjusted in the ExpSetter and that doesn't change, only the significand parts are converted from the original base `base` to the new base `base**base_scale`.

This will require adjusting the repeating digits position and length, and adding leading 0s (in the original base) to the signficant and/or trailing digits may be required.

Attributes

base_scale[R]
numeral[R]
scaled_base[R]

Public Class Methods

new(exp_setter, base_scale) click to toggle source
# File lib/numerals/format/base_scaler.rb, line 26
def initialize(exp_setter, base_scale)
  @setter = exp_setter
  @numeral = @setter.numeral
  @base_scale = base_scale
  @scaled_base = @setter.base**@base_scale
  adjust
end

Private Class Methods

ungrouped_digits(digits, base, base_scale) click to toggle source

Convert base digits to scaled base digits

# File lib/numerals/format/base_scaler.rb, line 147
def self.ungrouped_digits(digits, base, base_scale)
  digits.flat_map { |d|
    group = Digits[base: base]
    group.value = d
    ungrouped = group.digits_array
    if ungrouped.size < base_scale
      ungrouped = [0]*(base_scale - ungrouped.size) + ungrouped
    end
    ungrouped
  }
end

Public Instance Methods

base() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 43
def base
  scaled_base
end
fractional_insignificant_size() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 56
def fractional_insignificant_size
  if @setter.numeral.approximate?
    (@setter.fractional_insignificant_size + @scaling_trailing_size)/@base_scale
  else
    0
  end
end
fractional_part() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 47
def fractional_part
  ungrouped = @setter.fractional_part + (0...@scaling_trailing_size).map{|i| repeat_digit(i)}
  grouped_digits ungrouped
end
fractional_part_size() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 52
def fractional_part_size
  (@setter.fractional_part_size + @scaling_trailing_size)/@base_scale
end
integer_insignificant_size() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 73
def integer_insignificant_size
  if @setter.numeral.approximate?
    (@setter.integer_insignificant_size + @scaling_leading_size)/@base_scale
  else
    0
  end
end
integer_part() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 64
def integer_part
  ungrouped = [0]*@scaling_leading_size + @setter.integer_part
  grouped_digits ungrouped
end
integer_part_size() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 69
def integer_part_size
  (@setter.integer_part_size + @scaling_leading_size)/@base_scale
end
repeat_insignificant_size() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 85
def repeat_insignificant_size
  0
end
repeat_part() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 89
def repeat_part
  ungrouped = (@scaling_trailing_size...@scaling_trailing_size+@repeat_length).map{|i| repeat_digit(i)}
  grouped_digits ungrouped
end
repeat_size_size() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 81
def repeat_size_size
  @repeat_length/@base_scale
end

Private Instance Methods

adjust() click to toggle source
# File lib/numerals/format/base_scaler.rb, line 124
def adjust
  return if special?
  @setter_repeat_part = @setter.repeat_part
  @setter_repeat_part_size = @setter.repeat_part_size

  @scaling_trailing_size =  padding_size(@setter.fractional_part_size)
  @scaling_leading_size = padding_size(@setter.integer_part_size)

  @repeat_length = @setter.repeat_part_size
  while (@repeat_length % @base_scale) != 0
    @repeat_length += @setter.repeat_part_size
  end
end
grouped_digits(digits) click to toggle source

Convert base `exponent_base` digits to base `scaled_base` digits the number of digits must be a multiple of base_scale

# File lib/numerals/format/base_scaler.rb, line 111
def grouped_digits(digits)
  unless (digits.size % @base_scale) == 0
    raise "Invalid number of digits for group_digits (#{digits.size} is not a multiple of #{@base_scale})"
  end
  digits.each_slice(@base_scale).map{|group| scaled_digit(group)}
end
padding_size(digits_size) click to toggle source

Number of digits (base `exponent_base`) to be added to make the number of digits a multiple of `base_scale`.

# File lib/numerals/format/base_scaler.rb, line 120
def padding_size(digits_size)
  (@base_scale - digits_size) % @base_scale
end
repeat_digit(i) click to toggle source
# File lib/numerals/format/base_scaler.rb, line 138
def repeat_digit(i)
  if @setter_repeat_part_size > 0
    @setter_repeat_part[i % @setter_repeat_part_size]
  else
    0
  end
end
scaled_digit(group) click to toggle source

Return the `scaled_base` digit corresponding to a group of `base_scale` `exponent_base` digits

# File lib/numerals/format/base_scaler.rb, line 97
def scaled_digit(group)
  unless group.size == @base_scale
    raise "Invalid digits group size for scaled_digit (is #{group.size}; should be #{@base_scale})"
  end
  v = 0
  group.each do |digit|
    v *= @setter.base
    v += digit
  end
  v
end