Class: Lisp::Format::Directives::ExpFP

Inherits:
Directive show all
Defined in:
lib/carat/lisp-format.rb

Overview

Represents the ~E (Exponential floating-point) directive. This outputs floating point values in what is known as exponential or scientific floating point format, such as 1.0e+3 for 1000.

Instance Attribute Summary

Attributes inherited from Directive

#pos

Instance Method Summary collapse

Methods inherited from Directive

#initialize, #join

Constructor Details

This class inherits a constructor from Lisp::Format::Directives::Directive

Instance Method Details

#execute(state) ⇒ Object

Outputs the argument using exponential floating-point format. The full form is

~w,d,e,k,overflowchar,padchar,exponentchar@E

with the following interpretations

w (nil)

if non-nil, the output will be exactly w characters long,

d (nil)

if non-nil, this is the number of digits output after the decimal point (.),

e (nil)

if non-nil, the exponent part of the output will be exactly e characters long,

k (1)

scaling factor - the number is first scaled using this value,

overflowchar (nil)

if non-nil, this character is used when this directive would produce output longer than that specified with the w directive,

padchar (?s)

character to pad with if w is non-nil and output isn’t wide enough yet,

exponentchar (?e)

character to use for exponent divider,

@

numbers are always output with sign prepended.

An ArgumentError is raised if the argument is not a number or a string that can be converted to a number.



1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
# File 'lib/carat/lisp-format.rb', line 1065

def execute(state)
  width = param(0, state, nil)
  digits = param(1, state, nil)
  edigits = param(2, state, nil)
  scale = param(3, state, 1)
  overflowchar = param(4, state, nil)
  padchar = param(5, state, ?\s).chr
  exponentchar = param(6, state, ?e).chr
  arg = state.next_arg
  if arg.respond_to? :to_f
    num = arg.to_f
    sign = (num >= 0 and at_mod?) ? '+' : ''
    exp = Math.log10(num.abs).floor - (scale - 1)
    exp_str = exponentchar + (exp >= 0 ? '+' : '-') +
      (edigits.nil? ? exp.abs.to_s : exp.abs.to_s.rjust(edigits, '0'))
    if digits.nil? and width.nil? and edigits.nil?
      str = sign + (num * (10 ** -exp)).to_s + exp_str
    else
      if digits.nil?
        prec = width - sign.length -
          ((num * (10 ** -exp)).to_s.index(/\./) + 1) - exp_str.length
        str = sign + sprintf("%#.#{prec}f", num) + exp_str
      else
        if scale > 0
          if scale < digits + 2
            prec = digits - scale + 1
          else
            param_error 3, 'scale must be < digits + 2'
          end
        else
          prec = -scale + (digits + scale)
        end
        str = sign + sprintf("%#.#{prec}f", num * (10**-exp)) + exp_str
      end
      unless width.nil?
        if scale <= 0 and str.length > width
          str.sub!(/^([+-]?)0\./, '\1.')
        end
        str = str.rjust(width, padchar) if str.length < width
      end
      unless width.nil? and overflowchar.nil?
        if not edigits.nil? and (exp_str.length - 2) > edigits
          str = overflowchar.chr * width
        end
      end
    end
    state.output str
  elsif arg.respond_to? :to_int
    state.push_back_arg
    parameters = @params[0].nil? ? [] : [@params[0]]
    Factory.build(parameters, [], ?D, nil, @pos).execute(state)
  else
    arg_error 'argument is not a number or a number string'
  end
end