note description: "Formatter for non-integral numbers" library: "Free implementation of ELKS library" status: "See notice at end of class." legal: "See notice at end of class." names: format_double date: "$Date: 2016-12-05 17:39:47 +0000 (Mon, 05 Dec 2016) $" revision: "$Revision: 99631 $" class FORMAT_DOUBLE inherit FORMAT_INTEGER rename make as set_defaults, split as split_integral, formatted as fm_formatted export {NONE} fm_formatted redefine comma_separate, underscore_separate, remove_separator end DOUBLE_MATH export {NONE} all end create make feature -- Initialization make (w, d: INTEGER_32) require reasonable_field: w >= 1 reasonable_decimals: d <= w do set_defaults (w) decimals := d decimal := '.' trailing_zeros_shown := True ensure blank_fill: fill_character = ' ' show_sign_negative: show_sign_negative no_separator: no_separator width_set: width = w right_justified: right_justified leading_sign: leading_sign decimals_set: decimals = d decimal_point: decimal = '.' trailing_zeros_shown: trailing_zeros_shown end feature -- Access after_decimal_separate: BOOLEAN -- Use separators after the decimal? decimals: INTEGER_32 -- Number of digits after the decimal point. zero_not_shown: BOOLEAN -- Show 0.5 as .5 or 0.5? trailing_zeros_shown: BOOLEAN -- Show 0.5000 as 0.5 or 0.5000? decimal: CHARACTER_8 -- What is used for the decimal feature -- Status setting point_decimal -- Use . as the decimal point. do decimal := '.' ensure decimal = '.' end comma_decimal -- Use , as the decimal point. do decimal := ',' ensure decimal = ',' end set_decimals (d: INTEGER_32) -- d decimals to be displayed. require d <= width do decimals := d ensure decimals = d end separate_after_decimal -- Use separators after the decimal. do after_decimal_separate := True ensure after_decimal_separate end no_separate_after_decimal -- Do not use separators after the decimal. do after_decimal_separate := False ensure not after_decimal_separate end underscore_separate -- Set the separator to be underscore. do separator := '_' separate_after_decimal ensure then after_decimal_separate end comma_separate -- Set the separator to be comma. do separator := ',' separate_after_decimal ensure then after_decimal_separate end remove_separator -- Remove the separator. do separator := '%U' no_separate_after_decimal ensure then not after_decimal_separate end show_zero -- Show 0.5 as 0.5 . do zero_not_shown := False ensure not zero_not_shown end show_trailing_zeros -- Show 0.5000 as 0.5000. do trailing_zeros_shown := True ensure trailing_zeros_shown_set: trailing_zeros_shown end hide_zero -- Show 0.5 as .5 . do zero_not_shown := True ensure zero_not_shown end hide_trailing_zeros -- Show 0.5000 as 0.5, and 0.0000 as 0.0. do trailing_zeros_shown := False ensure trailing_zeros_shown_set: not trailing_zeros_shown end feature -- Conversion formatted (d: REAL_64): STRING_8 -- Format d. local sign: INTEGER_32 integral, fraction: REAL_64 ints, fracs: STRING_8 value: REAL_64 do value := d sign := 1 if d < 0.to_double then sign := -1 value := - value end value := value + 5.to_double * 10 ^ (- decimals - 1).to_double integral := floor (value) fraction := floor ((value - integral) * 10 ^ (decimals + 1).to_double) if not no_separator then ints := split_integral (integral.out) if after_decimal_separate then fracs := separate_fraction (pad_fraction (fraction)) else fracs := pad_fraction (fraction) end else ints := integral.out fracs := pad_fraction (fraction) end create Result.make (width) if integral /= 0.to_double or else not zero_not_shown then Result.append (ints) end if not Result.has ('e') then Result.extend (decimal) if decimals > 0 then Result.append (fracs) end if not ignore_sign then Result := process_sign (Result, sign) end end if justification /= No_justification and then Result.count < width then Result := justify (Result) end ensure exists: Result /= Void correct_length: not_justified or Result.count >= width end feature {NONE} -- Implementation pad_fraction (f: REAL_64): STRING_8 -- Stretch or shrink f to length decimals . local i: INTEGER_32 do Result := f.out; Result.remove_tail (1) if Result.count > decimals then Result := Result.substring (1, decimals) else from until Result.count = decimals loop Result.precede ('0') end end if not trailing_zeros_shown then from i := Result.count until i <= 1 or else Result.item (i) /= '0' loop Result.remove (i) i := i - 1 end end ensure valid_result: trailing_zeros_shown implies Result.count = decimals end separate_fraction (s: STRING_8): STRING_8 -- Apply separators to the fraction. require efficiency: separator /= '%U' local count, sep_length: INTEGER_32 do from count := 1 create Result.make (width) until count > s.count - 3 loop from sep_length := 0 until sep_length = 3 loop Result.extend (s.item (count)) count := count + 1 sep_length := sep_length + 1 end; Result.extend (separator) end from until count > s.count loop Result.extend (s.item (count)) count := count + 1 end end invariant separate_all: no_separator implies not after_decimal_separate note copyright: "Copyright (c) 1984-2012, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software 5949 Hollister Ave., Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end -- class FORMAT_DOUBLE
Generated by ISE EiffelStudio