This site contains older material on Eiffel. For the main Eiffel page, see http://www.eiffel.com.

EiffelBase class
(HTML page generated by ISE Eiffel 4.2)

Eiffel Class
indexing
	description: "Formatter for non-integral numbers";
	status: "See notice at end of class";
	names: format_double;
	date: "$Date: 2007-03-30 11:10:11 -0800 (Fri, 30 Mar 2007) $";
	revision: "$Revision: 95354 $"

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

creation
	make

feature -- Initialization

	make (w, d: INTEGER) is
		require
			reasonable_field: w >= 1;
			reasonable_decimals: d <= w
		do
			set_defaults (w);
			decimals := d;
			decimal := '.'
		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 = '.'
		end;

feature -- Access

	after_decimal_separate: BOOLEAN;
			-- Use separators after the decimal?

	decimals: INTEGER;
			-- Number of digits after the decimal point.

	zero_not_shown: BOOLEAN;
			-- Show 0.5 as .5 or 0.5?

	decimal: CHARACTER;
			-- What is used for the decimal

feature -- Status setting

	point_decimal is
			-- Use . as the decimal point.
		do
			decimal := '.'
		ensure
			decimal = '.'
		end;

	comma_decimal is
			-- Use , as the decimal point.
		do
			decimal := ','
		ensure
			decimal = ','
		end;

	set_decimals (d: INTEGER) is
			-- d decimals to be displayed.
		require
			d <= width
		do
			decimals := d
		ensure
			decimals = d
		end;

	separate_after_decimal is
			-- Use separators after the decimal.
		do
			after_decimal_separate := true
		ensure
			after_decimal_separate
		end;

	no_separate_after_decimal is
			-- Do not use separators after the decimal.
		do
			after_decimal_separate := false
		ensure
			notafter_decimal_separate
		end;

	underscore_separate is
			-- Set the separator to be underscore.
		do
			separator := '_';
			separate_after_decimal
		ensure
			after_decimal_separate
		end;

	comma_separate is
			-- Set the separator to be comma.
		do
			separator := ',';
			separate_after_decimal
		ensure
			after_decimal_separate
		end;

	remove_separator is
			-- Remove the separator.
		do
			separator := '%U';
			no_separate_after_decimal
		ensure
			notafter_decimal_separate
		end;

	show_zero is
			-- Show 0.5 as 0.5 .
		do
			zero_not_shown := false
		ensure
			notzero_not_shown
		end;

	hide_zero is
			-- Show 0.5 as .5 .
		do
			zero_not_shown := true
		ensure
			zero_not_shown
		end;

feature -- Conversion

	formatted (d: DOUBLE): STRING is
			-- Format d.
		local
			sign: INTEGER;
			integral, fraction: DOUBLE;
			ints, fracs: STRING;
			value: DOUBLE
		do
			value := d;
			sign := 1;
			if d < 0 then
				sign := -1;
				value := -value
			end;
			value := value + 5 * 10 ^ (-decimals - 1);
			integral := floor (value);
			fraction := floor ((value - integral) * 10 ^ (decimals + 1));
			if notno_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 := clone (integral.out);
				fracs := pad_fraction (fraction)
			end;
			create Result.make (width);
			if integral /= 0 or else notzero_not_shown then
				Result.append (ints)
			end;
			Result.extend (decimal);
			if decimals > 0 then
				Result.append (fracs)
			end;
			if notignore_sign then
				Result := process_sign (Result, sign)
			end;
			if justification /= no_justification and then Result.count < width then
				Result := justify (Result)
			end
		ensure
			exists: Result /= void;
			correct_width: Result.count >= width
		end;

feature {NONE} -- Implementation

	pad_fraction (f: DOUBLE): STRING is
			-- Stretch or shrink f to length decimals .
		do
			Result := f.out;
			Result.head (Result.count - 1);
			if Result.count > decimals then
				Result := Result.substring (1, decimals)
			else
				from
				until
					Result.count = decimals
				loop
					Result.precede ('0')
				end
			end
		ensure
			Result.count = decimals
		end;

	separate_fraction (s: STRING): STRING is
			-- Apply separators to the fraction.
		require
			efficiency: separator /= '%U'
		local
			count, sep_length: INTEGER
		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 notafter_decimal_separate;

end -- class FORMAT_DOUBLE