-
DayGaykin © (25.08.16 10:28) [0]Предлагается следующая задача:
Написать функцию MulDiv для 64х-битных знаковых аргументов.
Изначально задача поставлена для реализации на языке java: https://toster.ru/q/347954
Функция должна быть похожа на следующую:
function MulDiv(A, B, C: Int64):Int64;
begin
Result := A * B / C;
end;
со следующими условиями:
1. Функция должна корректно работать при A * B > High(Int64).
2. Если результат вычисления не "влезает" в Int64, функция должна "поднять" исключение.
3. Точность выполнения и метод округления должен совпадать с точностью и округлением обычной целочисленной арифметики (той, что "помещается" в типы).
4. В функции нельзя использовать числа с плавающей точкой.
5. Нельзя выполнять операции, которые приведут к использованию кучи.
6. Можно использовать только чистый паскаль. Ассемблер использовать нельзя.
7. Нельзя использовать возможность процессора умножать числа с переполнением. (Хотя не понятно как это можно использовать без ассемблера).
8. Нельзя использовать функции, которые сами не удовлетворяют условиям 4, 5, 6, 7, 8.
9. Желательно не использовать беззнаковые типы.
На Java я написал тест, для Delphi напишу тест чуть позже. -
NoUser © (25.08.16 16:18) [1]// System.pas
MulDivInt64(...); // ( _MulDivModInt64 )
Не? -
NoUser © (25.08.16 16:49) [2]зы.
п.2: противоречит п.1
п.3: что такое "округление обычной целочисленной арифметики"
п.4: хм, а ведь Max(Int64) = Int64(Double(NaN)) ;) -
DayGaykin © (25.08.16 16:49) [3]
> NoUser © (25.08.16 16:18) [1]
Уверены, что удовлетворяет условиям? -
DayGaykin © (25.08.16 16:51) [4]
> п.2: противоречит п.1
MaxInt64 * MaxInt64 / MaxInt64 - результат влезает в Int64,
хотя MaxInt64 * MaxInt64 - не влезает.
> п.3: что такое "округление обычной целочисленной арифметики"
А как вы думаете? -
NoUser © (25.08.16 17:03) [5]> Уверены, что удовлетворяет условиям?
Не знаю, а чё не так?
>> п.2: противоречит п.1
каюсь, прочитал как Если результат промежуточных вычислений
> А как вы думаете?
думаю, что "в обычной целочисленной арифметики" нет "округления" -
DayGaykin © (25.08.16 17:07) [6]
> думаю, что "в обычной целочисленной арифметики" нет "округления"
А что по вашему произойдет при вычислении:
intVariable = 3/2;
> Не знаю, а чё не так?
К сожалению, у меня нет delphi под рукой. Я уверен, что там или асм или вызов апишной функции. -
NoUser © (25.08.16 17:14) [7]> intVariable = 3/2;
"Incompatible types:" ?{$IF defined(CPUARM) or defined(CPUX86) or defined(EXTERNALLINKER)}
function _MulDivModInt64(AValue, AMul, ADiv: Int64; Remainder: PInt64): Int64;
var
HVal, Temp, LVal, HRes, LRes: UInt64;
Sign: Byte;
begin
// This function is used by division or multiply operator
// for scaling 'Comp' value
// eq. Result := Int64((Int128(AValue) * Int128(AMul)) div ADiv);
// or Result := Int64((Extended80(AValue) * Extended80(AMul)) / Extended80(ADiv));
Sign := 0;
if AValue < 0 then
begin
AValue := - AValue;
Sign := Sign xor 3;
end;
if AMul < 0 then
begin
AMul := - AMul;
Sign := Sign xor 1;
end;
if ADiv < 0 then
begin
ADiv := - ADiv;
Sign := Sign xor 1;
end;
//
// Int128(HVal:LVal) := Int128(AValue) * Int128(AMul);
//
HVal := UInt64(UInt32(AValue shr 32)) * UInt64(UInt32(AMul shr 32));
Temp := UInt64(UInt32(AValue shr 32)) * UInt64(UInt32(AMul))
+ UInt64(UInt32(AValue)) * UInt64(UInt32(AMul shr 32));
LVal := UInt64(UInt32(AValue)) * UInt64(UInt32(AMul));
Temp := Temp + (LVal shr 32);
LVal := (Temp shl 32) + UInt64(UInt32(LVal));
HVal := HVal + (Temp shr 32);
//
// Result := Int128(HVal:LVal) div ADiv;
//
//URes := HVal div UInt64(ADiv);
Temp := HVal mod UInt64(ADiv);
Temp := (Temp shl 32) + (LVal shr 32);
HRes := Temp div UInt64(ADiv);
Temp := Temp mod UInt64(ADiv);
Temp := (Temp shl 32) + UInt64(UInt32(LVal));
LRes := Temp div UInt64(ADiv);
Result := (HRes shl 32) + LRes;
if (Sign and 1) <> 0 then
Result := - Result;
if Assigned(Remainder) then
begin
Remainder^ := Temp mod UInt64(ADiv);
if (Sign and 2) <> 0 then
Remainder^ := - Remainder^;
end;
end;
{$ENDIF CPUARM or CPUX86}
за UInt-ы невзыщите )) -
DayGaykin © (25.08.16 19:11) [8]
> NoUser © (25.08.16 17:14) [7]
Интересно, изучу.
> > intVariable = 3/2;
>
> "Incompatible types:" ?
Прошу прощения, уже отвык немного от паскаля.
Имел ввиду: intVariable = 3 div 2