Class: Lisp::Format::Directives::GeneralFP

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

Overview

Represents the ~G (General floating-point) directive. This outputs its argument using either a format like ~F or ~E depending upon given parameters and the magnitude of the argument.

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 algorithm to decide what format to use looks something like

let
  10^n-1 <= arg < 10^n, or n = 0 if arg = 0,
  ee = e + 2, or ee = 4 if e undefined,
  ww = w - ee, or ww = nil if w undefined,
  dd = d - n, or dd = max(q, min(n, 7)) where q = number of

characters necessary to print arg without loss of information

in
  0 <= dd <= d, and print using

~ww,dd,,overflowchar,padcharF~ee@T

or print using

~w,d,e,k,overflowchar,padchar,exponentcharG Use of the @ modifier in the directives above depends on if it was passed to ~G in the first place.

The full form is

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

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.



1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
# File 'lib/carat/lisp-format.rb', line 1168

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)
  exponentchar = param(6, state, nil)
  arg = state.next_arg
  if arg.respond_to? :to_f
    num = arg.to_f
    n = num == 0.0 ? 0 : Math.log10(num.abs).floor + 1
    ee = edigits.nil? ? 4 : edigits + 2
    ww = w.nil? ? nil : w - ee
    if d.nil?
      q = num.to_s.length
      d = Math.max(q, Math.min(n, 7))
    end
    dd = d - n
    if 0 <= dd and dd <= d
      state.push_back_arg
      parameters = [
        Parameters::Integer.new(@pos, ww),
        Parameters::Integer.new(@pos, dd),
        Parameters::Default.new(@pos),
        overflowchar.nil? ?
          Parameters::Default.new(@pos) : 
          Parameters::Character.new(@pos, overflowchar),
        padchar.nil? ?
          Parameters::Default.new(@pos) :
          Parameters::Character.new(@pos, padchar),
      ]
      Factory.build(parameters, @modifiers, ?F, nil,
                    @pos).execute(state)
      Factory.build([Parameters::Integere.new(@pos, ee)], @modifiers,
                    ?T, nil, @pos).execute(state)
    else
      state.push_back_arg
      Factory.build(@params, @modifiers, ?E, nil, @pos).execute(state)
    end
  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