-- This file is free software, which comes along with SmartEiffel. This -- software is distributed in the hope that it will be useful, but WITHOUT -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -- FITNESS FOR A PARTICULAR PURPOSE. You can modify it as you want, provided -- this header is kept unaltered, and a notification of the changes is added. -- You are allowed to redistribute it and sell it, alone or as a part of -- another product. -- Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE -- Dominique COLNET and Suzanne COLLIN - SmartEiffel@loria.fr -- http://SmartEiffel.loria.fr -- deferred class NUMBER -- -- This abstract definition of a NUMBER is intended to be the unique -- view of the client (do not use sub-classes names at all in the -- client code). In order to create NUMBERs without using concrete -- class name, the client code can inherit NUMBER_TOOLS. (See directory -- ${SmartEiffel}/lib_show/number for example.) -- inherit HASHABLE undefine is_equal redefine fill_tagged_out_memory, out_in_tagged_out_memory end feature -- Binary operators for two NUMBERs: infix "+" (other: NUMBER): NUMBER is -- Sum of `Current' and `other'. require other /= Void deferred ensure Result /= Void end infix "-" (other: NUMBER): NUMBER is -- Difference of `Current' and `other'. require other /= Void do Result := Current + (- other) ensure Result /= Void end infix "*" (other: NUMBER): NUMBER is -- Product of `Current' and `other'. require other /= Void deferred ensure Result /= Void end infix "/" (other: NUMBER): NUMBER is -- Quotient of `Current' and `other'. require not (other @= 0) divisible(other) do Result := Current * other.inverse ensure Result /= Void end infix "//" (other: NUMBER): NUMBER is -- Divide `Current' by `other' (Integer division). require is_abstract_integer other.is_abstract_integer divisible (other) deferred ensure Result.is_abstract_integer end infix "\\" (other: NUMBER): NUMBER is -- Remainder of division of `Current' by `other'. require is_abstract_integer other.is_abstract_integer divisible (other) deferred ensure Result.is_abstract_integer end infix "^" (exp: NUMBER): NUMBER is -- `Current' raised to `exp'-th power. require exp.is_abstract_integer exp.is_positive not (is_zero and then exp.is_zero) local e: NUMBER factor: NUMBER do Result := one factor := Current from e := exp until e.is_zero loop if (e @\\ 2) @= 1 then Result := Result * factor end e := e @// 2 factor := factor * factor end ensure Result /= Void exp.is_zero implies Result.is_one end infix "<" (other: NUMBER): BOOLEAN is -- Is `Current' strictly less than `other'? require other_exists: other /= Void deferred ensure asymmetric: Result implies not (other <= Current) end infix "<=" (other: NUMBER): BOOLEAN is -- Is `Current' less or equal than `other'? require other_exists: other /= Void do Result := not (other < Current) ensure definition: Result = (Current < other) or is_equal(other) end infix ">" (other: NUMBER): BOOLEAN is -- Is `Current' strictly greater than `other'? require other_exists: other /= Void do Result := (other < Current) ensure definition: Result = (other < Current) end infix ">=" (other: NUMBER): BOOLEAN is -- Is `Current' greater or equal than `other'? require other_exists: other /= Void do Result := not (Current < other) ensure definition: Result = (other <= Current) end gcd(other: NUMBER): ABSTRACT_INTEGER is -- Great Common Divisor of `Current' and `other'. require other.is_abstract_integer is_abstract_integer is_positive other.is_positive do if other.is_zero then Result ?= Current check Result /= Void end else Result := other.gcd(Current \\ other) end end feature -- Unary operators for two NUMBERs: frozen prefix "+" : NUMBER is -- Unary plus of `Current'. do Result := Current ensure Result = Current end prefix "-" : NUMBER is -- Opposite of `Current'. deferred ensure Result /= Void end feature -- To know more about a NUMBER: in_range(lower, upper: NUMBER): BOOLEAN is -- Return true if `Current' is in range [`lower'..`upper'] do Result := (Current >= lower) and then (Current <= upper) ensure Result = (Current >= lower and Current <= upper) end compare(other: NUMBER): INTEGER is -- Compare `Current' with `other'. -- `<' <==> `Result < 0' -- `>' <==> `Result > 0' -- Otherwise `Result = 0'. require other /= Void do if (Current < other) then Result := -1 elseif (other < Current) then Result := 1 end ensure (Result < 0) = (Current < other) (Result = 0) = not (Current < other or Current > other) (Result > 0) = (Current > other) end min(other: NUMBER): NUMBER is -- Minimum of `Current' and `other'. require other /= Void do if Current < other then Result := Current else Result := other end ensure Result <= Current and then Result <= other compare(Result) = 0 or else other.compare(Result) = 0 end max(other: NUMBER): NUMBER is -- Maximum of `Current' and `other'. require other /= Void do if (other < Current) then Result := Current else Result := other end ensure (Result >= Current) and then (Result >= other) compare(Result) = 0 or else other.compare(Result) = 0 end is_zero: BOOLEAN is -- Is it 0 ? deferred ensure Result = (Current @= 0) end is_one: BOOLEAN is -- Is it 1 ? deferred ensure Result = (Current @= 1) end is_positive: BOOLEAN is -- Is `Current' greater or equal zero ? deferred ensure Result = (Current @>= 0) end is_negative: BOOLEAN is -- Is `Current' < 0 ? deferred ensure Result = (Current @< 0) end is_odd, odd: BOOLEAN is -- Is `odd' ? require is_abstract_integer do Result := (Current @\\ 2).is_one end is_even, even: BOOLEAN is -- Is `even' ? require is_abstract_integer do Result := (Current @\\ 2).is_zero end is_equal(other: NUMBER): BOOLEAN is deferred end frozen same_as(other: NUMBER): BOOLEAN is -- Is it the same NUMBER as `other' ? -- -- Note: because `is_equal' uses type like Current for -- `other', this is impossible to use directely `is_equal'. obsolete "You now have to use `is_equal' (18th nov. 2002)." require other /= Void do Result := is_equal(other) ensure Result implies other.is_equal(Current) end frozen is_abstract_integer: BOOLEAN is local abstract_integer: ABSTRACT_INTEGER do abstract_integer ?= Current Result := abstract_integer /= Void end frozen is_abstract_fraction: BOOLEAN is local abstract_fraction : ABSTRACT_FRACTION do abstract_fraction ?= Current Result := abstract_fraction /= Void end frozen is_integer: BOOLEAN is -- Does `Current' value fit on an INTEGER ? local abstract_integer: ABSTRACT_INTEGER do abstract_integer ?= Current if abstract_integer /= Void then Result := abstract_integer.is_integer_value end ensure Result implies is_abstract_integer end frozen is_double: BOOLEAN is do if Current #>= Minimum_double then Result := Current #<= Maximum_double end end feature -- Conversions and printing: to_integer: INTEGER is -- Conversion of `Current' in an INTEGER. require is_integer deferred end to_double: DOUBLE is -- Conversion of `Current' in a DOUBLE. require is_double deferred end frozen to_string: STRING is -- Convert the NUMBER into a new allocated STRING. -- Note: see also `append_in' to save memory. do Result := once "......... (This is a private buffer) ............" Result.clear append_in(Result) Result := Result.twin end append_in(buffer: STRING) is -- Append the equivalent of `to_string' at the end of `buffer'. -- Thus you can save memory because no other STRING is allocated -- for the job. require buffer /= Void deferred end frozen to_decimal(digits: INTEGER; all_digits: BOOLEAN): STRING is -- Convert `Current' into its decimal view. A maximum of decimal -- `digits' places will be used for the decimal part. If the -- `all_digits' flag is true insignificant digits will be included -- as well. (See also `decimal_in' to save memory.) require non_negative_digits: digits >= 0 do Result := once "This is a local STRING buffer ...." Result.clear append_decimal_in(Result,digits,all_digits) Result := Result.twin ensure not Result.is_empty end append_decimal_in(buffer: STRING; digits: INTEGER; all_digits: BOOLEAN) is -- Append the equivalent of `to_decimal' at the end of `buffer'. Thus -- you can save memory because no other STRING is allocated. require non_negative_digits: digits >= 0 deferred end frozen digit: CHARACTER is -- Gives the corresponding CHARACTER for range 0..9. require to_integer.in_range(0,9) do Result := to_integer.digit ensure (once "0123456789").has(Result) Current @= Result.value end feature -- To mimic NUMERIC: divisible(other: NUMBER): BOOLEAN is -- Is `other' a valid divisor for `Current' ? require other /= Void do Result := not other.is_zero end one: NUMBER is -- The neutral element of multiplication. once !SMALL_INTEGER!Result.make(1) ensure neutral_element: -- Result is the neutral element of -- multiplication. end zero: NUMBER is -- The neutral element of addition. once !SMALL_INTEGER!Result.make(0) ensure neutral_element: -- Result is the neutral element of -- addition. end frozen sign: INTEGER is do if is_positive then Result := 1 elseif is_negative then Result := - 1 end end sqrt: DOUBLE is -- Compute the square routine. require is_double do Result := to_double.sqrt end frozen log: DOUBLE is require is_double do Result := to_double.log end abs: NUMBER is do if is_negative then Result := -Current else Result := Current end end feature -- To mix NUMBER and INTEGER: infix "@+" (other: INTEGER): NUMBER is -- Sum of `Current' and `other'. deferred ensure Result /= Void end infix "@-" (other: INTEGER): NUMBER is -- Difference of `Current' and `other'. do if other = Minimum_integer then Result := (Current @+ 1) Result := Result @+ Maximum_integer else Result := Current @+ (- other) end ensure Result /= Void end infix "@*" (other: INTEGER): NUMBER is require other /= Void deferred ensure Result /= Void end infix "@/" (other: INTEGER): NUMBER is -- Quotient of `Current' and `other'. require other /= 0 deferred ensure Result /= Void end infix "@//" (other: INTEGER): NUMBER is -- Divide `Current' by `other' (Integer division). require is_abstract_integer other /= 0 deferred ensure Result.is_abstract_integer end infix "@\\" (other: INTEGER): NUMBER is -- Remainder of division of `Current' by `other'. require is_abstract_integer other /= 0 deferred ensure Result.is_abstract_integer end infix "@^" (exp: INTEGER): NUMBER is require (exp > 0) or else not is_zero local int : INTEGER other : NUMBER do int := exp.abs inspect int when 0 then !SMALL_INTEGER!Result.make(1) when 1 then Result := Current else from int := int - 1 other := Current Result := Current until int < 2 loop if int.odd then Result := Result * other end other := other * other; -- methode sqrt : ^2 int := int // 2 end Result := Result * other end if (exp < 0) then Result := Result.inverse end ensure Result /= Void Result /= Current implies (exp /= 1 or else not is_zero) end infix "@=" (other: INTEGER): BOOLEAN is -- Is `Current' equal `other' ? deferred end infix "@<" (other: INTEGER): BOOLEAN is -- Is `Current' strictly less than `other'? deferred ensure Result = not (Current @>= other) end infix "@<=" (other: INTEGER): BOOLEAN is -- Is `Current' less or equal `other'? deferred ensure Result = not (Current @> other) end infix "@>" (other: INTEGER): BOOLEAN is -- Is `Current' strictly greater than `other'? deferred ensure Result = not (Current @<= other) end infix "@>=" (other: INTEGER): BOOLEAN is -- Is `Current' greater or equal than `other'? deferred ensure Result = not (Current @< other) end feature -- To mix NUMBER and DOUBLE: infix "#=" (other: DOUBLE): BOOLEAN is -- Is `Current' equal `other'? deferred end infix "#<" (other: DOUBLE): BOOLEAN is -- Is `Current' strictly less than `other'? deferred ensure Result implies not (Current #>= other) end infix "#<=" (other: DOUBLE): BOOLEAN is -- Is `Current' less or equal `other'? deferred ensure Result = not (Current #> other) end infix "#>" (other: DOUBLE): BOOLEAN is -- Is `Current' strictly greater than `other'? deferred ensure Result = not (Current #<= other) end infix "#>=" (other: DOUBLE): BOOLEAN is -- Is `Current' greater or equal than `other'? deferred ensure Result = not (Current #< other) end feature -- Misc: out_in_tagged_out_memory, fill_tagged_out_memory is do append_in(tagged_out_memory) end hash_code: INTEGER is do if is_double then Result := to_double.hash_code else not_yet_implemented end end inverse: NUMBER is require divisible(Current) deferred ensure Result /= Void end factorial: NUMBER is require is_abstract_integer is_positive local n: NUMBER do if is_zero then !SMALL_INTEGER!Result.make(1) else from Result := Current n := Current @- 1 until n @= 0 loop Result := n * Result n := n @- 1 end end ensure Result.is_abstract_integer Result.is_positive end feature {NUMBER} -- Implementation: nb_c(int: INTEGER): INTEGER is -- Return the number of chiffers in int. local i: INTEGER do from i := int Result := 1 until i < 10 loop i := i // 10 Result := Result + 1 end end frozen is_small_integer: BOOLEAN is -- Does `Current' value fit on an INTEGER ? do if is_abstract_integer then if Current @<= (Base - 1) then Result := Current @>= (- (Base - 1)) end end ensure Result implies is_abstract_integer end frozen add_with_small_integer(other: SMALL_INTEGER): NUMBER is require other /= Void do Result := Current @+ other.to_integer ensure Result /= Void end add_with_large_positive_integer(other: LARGE_POSITIVE_INTEGER): NUMBER is require other /= Void deferred ensure Result /= Void end add_with_large_negative_integer(other: LARGE_NEGATIVE_INTEGER): NUMBER is require other /= Void deferred ensure Result /= Void end add_with_small_fraction(other: INTEGER_FRACTION): NUMBER is require other /= Void deferred ensure Result /= Void end add_with_large_fraction(other: NUMBER_FRACTION): NUMBER is require other /= Void deferred ensure Result /= Void end multiply_with_small_integer(other: SMALL_INTEGER): NUMBER is require other /= Void do Result := Current @* other.to_integer ensure Result /= Void end multiply_with_large_positive_integer(other: LARGE_POSITIVE_INTEGER): NUMBER is require other /= Void deferred ensure Result /= Void end multiply_with_large_negative_integer(other: LARGE_NEGATIVE_INTEGER): NUMBER is require other /= Void deferred ensure Result /= Void end multiply_with_small_fraction(other: INTEGER_FRACTION): NUMBER is require other /= Void deferred ensure Result /= Void end multiply_with_large_fraction(other: NUMBER_FRACTION): NUMBER is require other /= Void deferred ensure Result /= Void end greater_with_small_integer(other: SMALL_INTEGER): BOOLEAN is require other /= Void do Result := Current @> other.to_integer end greater_with_large_positive_integer(other: LARGE_POSITIVE_INTEGER): BOOLEAN is require other /= Void deferred end greater_with_large_negative_integer(other: LARGE_NEGATIVE_INTEGER): BOOLEAN is require other /= Void deferred end greater_with_small_fraction(other: INTEGER_FRACTION): BOOLEAN is require other /= Void deferred end greater_with_large_fraction(other: NUMBER_FRACTION): BOOLEAN is require other /= Void deferred end feature {NONE} max_double: NUMBER is local nt: NUMBER_TOOLS tmp: STRING once tmp := "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" tmp.clear Maximum_double.append_in_format(tmp,0) Result := nt.from_string(tmp) end min_double: NUMBER is local nt: NUMBER_TOOLS tmp: STRING once tmp := "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" tmp.clear Minimum_double.append_in_format(tmp,0) Result := nt.from_string(tmp) end greater_large_negative_integer: LARGE_NEGATIVE_INTEGER is once !LARGE_NEGATIVE_INTEGER!Result.make_smaller(0) end Base: INTEGER is -- The Base is the grater number which is like 10^x and -- which is inferior to the Maximum_integer value. -- -- So if Maximum_number is 2147483647 : -- The Base is : 1000000000. -- A number has a value between 0-9 so a number in a -- item of a FIXED_ARRAY[INTEGER] must be a succession -- of 9 so the value of the greater item is 999999999. -- And the Base is the greater value of a item + 1. once Result := (10 ^ (nb_c(Maximum_integer) - 1)).to_integer end; -- Base Half_base: INTEGER is -- It's the value of the greater number like 10^x which is -- inferior to Base.sqrt -- For the multiplication, we can make multiplication without -- depassement of capacity. once Result := (10^(Base.sqrt.log10.truncated_to_integer)).to_integer end Half_base_2: INTEGER is once Result := (Half_base ^ 2).to_integer end Rest_base: INTEGER is once Result := Base // (Half_base ^ 2).to_integer end Double_base: DOUBLE is -- It's the double value of the Base. -- The conversion integer to double of the Base value. -- This value is necessary to the division. once Result := Base.to_double end Log_base: DOUBLE is once Result := Base.log end Base_is_impair: BOOLEAN is once Result := (Rest_base = 10) end -- This global variable is necessary to have a good memory gestion temp_2_digints: FIXED_ARRAY[INTEGER] is -- Global variable to put an integer in a large_integer once !!Result.make(2) end temp_1_digint: FIXED_ARRAY[INTEGER] is -- Global varaible to put an integer in a small_integer -- for few operations once !!Result.make(1) end temp_from_mult: FIXED_ARRAY[INTEGER] is -- Global variable once !!Result.make(0) end temp_after_mult: FIXED_ARRAY[INTEGER] is -- Global variable once !!Result.make(0) end temp_quotient: FIXED_ARRAY[INTEGER] is -- Global variable once !!Result.make(0) end temp_remainder: FIXED_ARRAY[INTEGER] is -- Global variable once !!Result.make(0) end temp_division: FIXED_ARRAY[INTEGER] is -- Global variable once !!Result.make(0) end end -- NUMBER