delphi中变量溢出的捕获
我正在编写一个程序,显示从0到max的所有值。其中max是用户键入的值。我已经得到了所有的代码,现在我正在努力改进它。因此,我有几个问题delphi中变量溢出的捕获,delphi,math,compare,try-catch,overflow,Delphi,Math,Compare,Try Catch,Overflow,我正在编写一个程序,显示从0到max的所有值。其中max是用户键入的值。我已经得到了所有的代码,现在我正在努力改进它。因此,我有几个问题 我需要检查数字的每一个数字,并使它们成为第n次方。所以我决定创建一个选项卡[0..9],它包含从indexOfTab到n次方的索引,然后当我对数字中的所有数字求和时,它的工作原理如下: sum := sum + tab[x]; //where x is the digit that is currently checked 现在我想知道比较是否比这更快:
- 我需要检查数字的每一个数字,并使它们成为第n次方。所以我决定创建一个选项卡[0..9],它包含从indexOfTab到n次方的索引,然后当我对数字中的所有数字求和时,它的工作原理如下:
现在我想知道比较是否比这更快:sum := sum + tab[x]; //where x is the digit that is currently checked
sum:= sum + power(x,n);
- 我还想抓住如果和溢出。我知道如果。。然后。但我想知道是否有一种方法可以不检查每一个操作,如果总和改变符号,只有程序会捕捉到这个变量溢出,然后它会做一些代码
编辑:
首先,使用值表的方法将是迄今为止最快的方法。至于溢油的问题,我想稍后再谈 如果你真的想跑得尽可能快,有一些方法可以通过稍微分析一下问题来加快速度。当你知道如何找到一个值时,你很容易假设要找到所有的值,你只需要迭代所有的值,直到你的最大值。我担心,这很少是真的是有效的,就是这样的情况 要知道这是真的,只需考虑计算数字1034、1304、1403和1340。所有的计算实际上都是完全相同的,因此我们可以通过只检查按降序排列的数字(在我们的例子4310中)大大减少计算量。计算完4^4+3^4+1^4+0^4后,我们只需检查结果是否包含数字4、3、1和0。如果是这样,那么计算出来的数字就是自恋。这个概念也有助于最小化溢出测试,因为它意味着如果8000个溢出,甚至检查更大的数字都没有意义。另一方面,在短路和通过if语句引入复杂性之间有一个平衡 缺点是数字不是按顺序生成的,因此可能需要在最后进行某种排序。(我没有这样做)。不过,从正面来看,它允许使用并行for循环。实际上,这并没有节省太多时间(在我的机器上可能是10%),因为使用多个线程的开销在很大程度上抵消了并行处理的收益。下面的代码显示了这两种方法 下面的程序允许用户输入一些数字(而不是最大值)进行测试,并处理溢出。我这样做是为了简化编码。在我的计算机计算中,所有19位数字的自恋<2^63大约需要6秒
unit UnitNarcisistCalc;
interface
uses
System.Classes,
System.SysUtils,
System.Threading,
System.SyncObjs;
type
TCalcArray = array[ 0..9] of int64;
TNarcisistCalc = class
(* Calculated narcisistic number of a certain size *)
private
class function CheckResult( const pSum : int64; const DigitsUsed : TCalcArray; const DigitCount : integer ) : boolean;
class procedure AddADigit( const pDigit, pDigitsLeft : integer; const pSumSoFar : int64;
const pPowers, DigitsUsed : TCalcArray;
const pResults : TStrings; const DigitCount : integer );
protected
public
class procedure CalcNos( const pOfSize : integer; const pResults : TStrings;
pParallel : boolean );
end;
implementation
{ TNarcisistCalc }
class procedure TNarcisistCalc.AddADigit(const pDigit, pDigitsLeft: integer;
const pSumSoFar: int64; const pPowers, DigitsUsed: TCalcArray;
const pResults: TStrings; const DigitCount : integer );
var
iNewSum : int64;
i : integer;
iDigitsUsed : TCalcArray;
iOverflowMsg : string;
j: Integer;
begin
{
This recursive function builds the sum progressively until
pDigitsLeft = 0; We are careful to make all parameters const
so we don't accidently reuse anything.
}
iDigitsUsed := DigitsUsed;
iNewSum := pSumSoFar + pPowers[ pDigit ];
inc( iDigitsUsed[ pDigit ]);
if iNewSum < 0 then
begin
// overflow - so ditch this strand.
iOverflowMsg := 'Overflowed while evaluating ';
for i := 9 downto 0 do
begin
for j := 1 to iDigitsUsed[ i ] do
begin
iOverflowMsg := iOverflowMsg+ IntToStr( i );
end;
end;
pResults.Add( iOverflowMsg );
exit;
end;
if pDigitsLeft > 1 then // because we are not descrementing pDigitsLeft left even though logically we should
begin
for i := 0 to pDigit do
begin
AddADigit( i, pDigitsLeft - 1, iNewSum, pPowers, iDigitsUsed, pResults, DigitCount + 1 );
end;
end
else
begin
// lowest level
if CheckResult( pSumSoFar, iDigitsUsed, DigitCount + 1 ) then
begin
pResults.Add( IntToStr( pSumSoFar ));
end;
end;
end;
class procedure TNarcisistCalc.CalcNos(const pOfSize: integer;
const pResults: TStrings; pParallel : boolean);
var
fPowers : TCalcArray;
fUsed : TCalcArray;
i: Integer;
j: Integer;
iMaxDigit : integer;
iOverflow : Boolean;
iSum : int64;
iOverflowMsg : string;
iStrings : array[ 0.. 9 ] of TStringList;
begin
// calculate the powwers
pResults.Clear;
iOverFlow := FALSE;
iMaxDigit := 0;
for i := 0 to 9 do
begin
fPowers[ i ] := i;
fUsed[ i ] := 0;
for j := 2 to pOfSize do
begin
fPowers[ i ] := fPowers[ i ] * i;
if fPowers[ i ] < 0 then
begin
// overflow
iOverflow := TRUE;
iOverflowMsg := 'Overflowed while evaluating ' + IntToStr( i ) + '^' + IntToStr( pOfSize );
pResults.Add( iOverflowMsg );
break;
end;
end;
if iOverflow then
begin
break;
end
else
begin
iMaxDigit := i;
end;
end;
// we have set up our tabs and also prepared to not test any digits that
// would automatically give an overflow
if pParallel then
begin
TParallel.&For( 1, iMaxDigit, procedure(I : Integer )
var
iSum : int64;
begin
iStrings[ i ] := TStringList.Create;
iSum := 0;
AddADigit( i, pOfSize, iSum, fPowers, fUsed, iStrings[ i ], 0 );
end);
for i := 1 to iMaxDigit do
begin
pResults.AddStrings( iStrings[ i ]);
iStrings[ i ].Free;
end;
end
else
begin
for i := 1 to iMaxDigit do
begin
iSum := 0;
AddADigit( i, pOfSize, iSum, fPowers, fUsed, pResults, 0 );
end;
end;
end;
class function TNarcisistCalc.CheckResult(const pSum: int64;
const DigitsUsed: TCalcArray; const DigitCount : integer): boolean;
var
iDigitsUsed : TCalcArray;
iDigit, iSum : int64;
iDigitCount : integer;
begin
{ what we are doing here is checking if pSum contains the
same digits that were used to create it in the first place. }
iDigitsUsed := DigitsUsed;
iDigitCount := DigitCount;
iSum := pSum;
while iSum > 0 do
begin
iDigit := iSum mod 10;
iSum := iSum Div 10;
if iDigitsUsed[ iDigit ] > 0 then
begin
dec( iDigitsUsed[ iDigit ]);
dec( iDigitCount );
end
else
begin
Result := FALSE;
exit;
end;
end;
Result := iDigitCount = 0;
end;
end.
unitunit UnitNarcisistCalc;
接口
使用
系统,班级,,
System.SysUtils,
系统线程,
System.SyncObjs;
类型
TCalcArray=int64的数组[0..9];
tnarcistcalc=类
(*计算出的特定尺寸的麻醉次数*)
私有的
类函数CheckResult(const pSum:int64;const DigitsUsed:TCalcArray;const digitscount:integer):布尔;
类过程AddADigit(const-pDigit,pdigitsleet:integer;const-pSumSoFar:int64;
const pPowers,数字应用:TCalcArray;
const pResults:t字符串;const DigitCount:integer);
受保护的
公众的
类过程CalcNos(constpofsize:integer;constpresults:TStrings;
pParallel:布尔值);
结束;
实施
{tnarcistcalc}
类过程tnarcistcalc.AddADigit(const pDigit,pdigitsleet:integer;
常数pSumSoFar:int64;常数pPowers,数字使用:TCalcArray;
const pResults:t字符串;const DigitCount:integer);
变量
iNewSum:int64;
i:整数;
i使用:TCalcArray;
iOverflowMsg:字符串;
j:整数;
开始
{
此递归函数逐步生成和,直到
pDigitsLeft=0;我们小心地将所有参数设置为常量
所以我们不会意外地重复使用任何东西。
}
iDigitsUsed:=使用的数字;
iNewSum:=pSumSoFar+pPowers[pDigit];
股份有限公司(iDigitsUsed[pDigit]);
如果iNewSum<0,则
开始
//溢出-所以把这条河扔掉。
iOverflowMsg:=“计算时溢出”;
对于i:=9到0 do
开始
对于j:=1,我使用[i]do
开始
iOverflowMsg:=iOverflowMsg+IntToStr(i);
结束;
结束;
添加(iOverflowMsg);
出口
结束;
如果pDigitsLeft>1,则//因为我们没有定义pDigitsLeft,即使在逻辑上我们应该这样做
开始
对于i:=0,则pDigit do
开始
AddADigit(i,pDigitsLeft-1,iNewSum,pPowers,iDigitsUsed,pResults,DigitCount+1);
结束;
结束
其他的
开始
//最低水平
如果检查结果(pSumSoFar、iDigitsUsed、DigitCount+1),则
开始
加上(IntToStr(pSumSoFar));
结束;
结束;
结束;
类过程tnarcistcalc.CalcNos(constpofsize:integer;
常量预设值:t字符串;pParallel:布尔值);
变量
权力:TCalcArray;
融合:TCalcArray;
i:整数;
j:整数;
iMaxDigit:整数;
iOverflow:布尔;
iSum:int64;
iOverflowMsg:字符串;
iStrings:TStringList的数组[0..9];
开始
//计算功率
假定。明确;
iOverFlow:=假;
iMaxDigit:=0;
对于i:=0到9 do
开始
fPowers[i]:=i;
融合[i]:=0;
对于j:=2以pOfSize do
开始
fPowers[i]:=fPowers[i]*i;
如果fPowers[i]<0,则
开始
//溢出
iOverflow:=真;
iOverflowMsg:='计算'+IntToStr(i)+'^'+IntToStr(pOfSize)时溢出;
添加(iOverflowMsg);
打破
结束;
结束;
如果是流动的话
开始
打破
结束
其他的
开始
iMaxDigit:=i;
结束;
结束;
//我们已经设置了标签,也准备不测试任何
//你会自动给我吗
unit UnitNarcisistCalc;
interface
uses
System.Classes,
System.SysUtils,
System.Threading,
System.SyncObjs;
type
TCalcArray = array[ 0..9] of int64;
TNarcisistCalc = class
(* Calculated narcisistic number of a certain size *)
private
class function CheckResult( const pSum : int64; const DigitsUsed : TCalcArray; const DigitCount : integer ) : boolean;
class procedure AddADigit( const pDigit, pDigitsLeft : integer; const pSumSoFar : int64;
const pPowers, DigitsUsed : TCalcArray;
const pResults : TStrings; const DigitCount : integer );
protected
public
class procedure CalcNos( const pOfSize : integer; const pResults : TStrings;
pParallel : boolean );
end;
implementation
{ TNarcisistCalc }
class procedure TNarcisistCalc.AddADigit(const pDigit, pDigitsLeft: integer;
const pSumSoFar: int64; const pPowers, DigitsUsed: TCalcArray;
const pResults: TStrings; const DigitCount : integer );
var
iNewSum : int64;
i : integer;
iDigitsUsed : TCalcArray;
iOverflowMsg : string;
j: Integer;
begin
{
This recursive function builds the sum progressively until
pDigitsLeft = 0; We are careful to make all parameters const
so we don't accidently reuse anything.
}
iDigitsUsed := DigitsUsed;
iNewSum := pSumSoFar + pPowers[ pDigit ];
inc( iDigitsUsed[ pDigit ]);
if iNewSum < 0 then
begin
// overflow - so ditch this strand.
iOverflowMsg := 'Overflowed while evaluating ';
for i := 9 downto 0 do
begin
for j := 1 to iDigitsUsed[ i ] do
begin
iOverflowMsg := iOverflowMsg+ IntToStr( i );
end;
end;
pResults.Add( iOverflowMsg );
exit;
end;
if pDigitsLeft > 1 then // because we are not descrementing pDigitsLeft left even though logically we should
begin
for i := 0 to pDigit do
begin
AddADigit( i, pDigitsLeft - 1, iNewSum, pPowers, iDigitsUsed, pResults, DigitCount + 1 );
end;
end
else
begin
// lowest level
if CheckResult( pSumSoFar, iDigitsUsed, DigitCount + 1 ) then
begin
pResults.Add( IntToStr( pSumSoFar ));
end;
end;
end;
class procedure TNarcisistCalc.CalcNos(const pOfSize: integer;
const pResults: TStrings; pParallel : boolean);
var
fPowers : TCalcArray;
fUsed : TCalcArray;
i: Integer;
j: Integer;
iMaxDigit : integer;
iOverflow : Boolean;
iSum : int64;
iOverflowMsg : string;
iStrings : array[ 0.. 9 ] of TStringList;
begin
// calculate the powwers
pResults.Clear;
iOverFlow := FALSE;
iMaxDigit := 0;
for i := 0 to 9 do
begin
fPowers[ i ] := i;
fUsed[ i ] := 0;
for j := 2 to pOfSize do
begin
fPowers[ i ] := fPowers[ i ] * i;
if fPowers[ i ] < 0 then
begin
// overflow
iOverflow := TRUE;
iOverflowMsg := 'Overflowed while evaluating ' + IntToStr( i ) + '^' + IntToStr( pOfSize );
pResults.Add( iOverflowMsg );
break;
end;
end;
if iOverflow then
begin
break;
end
else
begin
iMaxDigit := i;
end;
end;
// we have set up our tabs and also prepared to not test any digits that
// would automatically give an overflow
if pParallel then
begin
TParallel.&For( 1, iMaxDigit, procedure(I : Integer )
var
iSum : int64;
begin
iStrings[ i ] := TStringList.Create;
iSum := 0;
AddADigit( i, pOfSize, iSum, fPowers, fUsed, iStrings[ i ], 0 );
end);
for i := 1 to iMaxDigit do
begin
pResults.AddStrings( iStrings[ i ]);
iStrings[ i ].Free;
end;
end
else
begin
for i := 1 to iMaxDigit do
begin
iSum := 0;
AddADigit( i, pOfSize, iSum, fPowers, fUsed, pResults, 0 );
end;
end;
end;
class function TNarcisistCalc.CheckResult(const pSum: int64;
const DigitsUsed: TCalcArray; const DigitCount : integer): boolean;
var
iDigitsUsed : TCalcArray;
iDigit, iSum : int64;
iDigitCount : integer;
begin
{ what we are doing here is checking if pSum contains the
same digits that were used to create it in the first place. }
iDigitsUsed := DigitsUsed;
iDigitCount := DigitCount;
iSum := pSum;
while iSum > 0 do
begin
iDigit := iSum mod 10;
iSum := iSum Div 10;
if iDigitsUsed[ iDigit ] > 0 then
begin
dec( iDigitsUsed[ iDigit ]);
dec( iDigitCount );
end
else
begin
Result := FALSE;
exit;
end;
end;
Result := iDigitCount = 0;
end;
end.