[erlang-questions] Proposal regarding integer arithmetic

Richard O'Keefe ok@REDACTED
Tue Nov 22 03:08:02 CET 2011


Hardware implementations of integer division often provide
both the quotient and the remainder.  (See the x86 DIV and IDIV
instructions, for example.)  Software implementations of bignum
division also commonly compute both the quotient and the remainder,
discarding one at the last minute.

Pop-2's integer division provided both quotient and remainder.
Common Lisp's

	(floor N D)    => floor(N/D),    N-D*floor(N/D)
	(ceiling N D)  => ceiling(N/D),  N-D*ceiling(N/D)
	(truncate N D) => truncate(N/D), N-D*truncate(N/D)
	(round N D)    => round(N/D),    N-D*round(N/D)

have long struck me as the right thing to do.

If we had a bunch of functions similar to
	truncate(N, D) when integer(N), integer(D), D =/= 0 ->
	    {N div D, N rem D}.
then the apparent inefficiency in
	{Q,_} = truncate(N, D)
or	{_,R} = truncate(N, D)
need only be apparent, not real.

The one argument against returning both the quotient and the remainder
is Knuth's argument for defining X mod 0 to be X.

One operation I've wanted is 'lac' (short for 'lacuna' and letter-shift
related to 'mod'):
	N lac D = D*ceiling(N/D) - N.
That answers the question "how much do I need to add to N to make it
a multiple of D?"

Masatake Daimon is right that 'div' and 'mod' should be precisely
documented.  Back when the formal specification of Erlang was being
written, there was a proposal that it should be linked to LIA-1.
Masatake Daimon may be pleased to hear that LIA-1 has recently been
revised and that truncating division has been either deprecated or
removed from the standard, I'm not sure which.
>> 
>> 
>> *** Proposal for new BIFs, math:floor/1 and math:ceil/1 ***
>> 
>> Why not having math:floor/1 and math:ceil/1? They truncate the
>> argument towards negative and positive infinity, respectively. Here is
>> an implementation in Erlang but these should be BIFs:
>> 
>>  -spec floor(number()) -> integer().
>>  floor(X) ->
>>      Y = trunc(X),
>>      case X - Y of
>>          Neg when Neg < 0 -> Y - 1;
>>          _ -> Y
>>      end.
>> 
>>  -spec ceil(number()) -> integer().
>>  ceil(X) ->
>>      Y = trunc(X),
>>      case X - Y of
>>          Pos when Pos > 0 -> Y + 1;
>>          _ -> Y
>>      end.

There is a question about what floor/1 and ceil[ing]/1 should return.
The floor() and ceil() functions in C return floats.
Erlang _can_ return integers because it has bignums.

But there are reasons why Common Lisp has ffloor, fceiling, fround, and
ftruncate as well as floor, ceiling, round, and truncate.

>> 
>> *** Proposal for an improvement of the function math:pow/2 ***
>> 
>> Currently math:pow/2 always returns float() for any arguments, but it
>> should compute the result in integer() when the base is integer() and
>> the exponent is non_neg_integer().

Floating point exponentiation and raising to an integer power are just
plain DIFFERENT FUNCTIONS and should not be overloaded on the same name.

Smalltalk has _ raisedTo: _  and _ raisedToInteger: _
Haskell has 
(^) :: (Num a, Integral b) => a -> b -> a
(**) :: (Floating a) => a -> a -> a

I think it would be better if math: remained a predominantly floating-point
resource, and a new integer: module were added.

>> 
>> *** Proposal for a new BIF, math:gcd/2 ***

This and lcm also belong in the integer: module, not the math: module.





More information about the erlang-questions mailing list