math - Catch if variable overflow in delphi -
i'm working on program shows narcissistic numbers 0 max. max value typed user. got code trying improve it. due have few questions.
i need check every digit of number , make them n-th power. decided create tab[0..9] contains indexoftab n-th power , when sum digits number works that:
sum := sum + tab[x]; //where x digit checked
now wondering if comparing faster this:
sum:= sum + power(x,n);
i want catch if sum overflow. , know how
if .. then
. wondering if there way not checking on every operation if sum change sign, program catch variable overflowed , code.
edit:
while (tmpnum>0) //tmpnum - digit of currenlty checked number(curnum) begin try suma:= suma+tab[tmpnum mod 10]; //suma =0 //tab[x] = x^(curnum.length); except suma:= 0; tmpnum:=0; //here more end; tmpnum:= tmpnum div 10; //divide number next modulo end;
first of method of using table of values far fastest method use. far overflow concerned, come shortly.
if serious running fast possible, there ways of making things go faster analysing problem little. tempting assume find values when know how find one, need iterate through values max. true efficient, afraid, , such case.
to see true, think calculating numbers 1034, 1304, 1403 , 1340. calculations same, can reduce our calculations substantially examining digits going in descending order (in our case 4310). having calculated 4^4 + 3^4 + 1^ 4 + 0^4 need check result contains digits 4,3,1 , 0. if number calculated narcissistic. notion helps minimising overflow tests, because means if 8000, example overflows, there no point in checking larger numbers. on other hand there balance between short circuiting, , introducing complexity through if statement.
the down side numbers not generated in order, sort of sorting may required @ end. (i have not done this). on upside, though, allows parallel loop used. in practice did not save time (maybe 10% on machine) because overheads of using multiple threads largely offset gains in doing things in parallel. code below shows both ways.
the program below allows user input number of digits (rather maximum value) test , deals overflows. did simplicity of coding. on machine calculation 19 digit narcissistic < 2^63 took 6 seconds.
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 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; : integer; idigitsused : tcalcarray; ioverflowmsg : string; j: integer; begin { recursive function builds sum progressively until pdigitsleft = 0; careful make parameters const don't accidently reuse anything. } idigitsused := digitsused; inewsum := psumsofar + ppowers[ pdigit ]; inc( idigitsused[ pdigit ]); if inewsum < 0 begin // overflow - ditch strand. ioverflowmsg := 'overflowed while evaluating '; := 9 downto 0 begin j := 1 idigitsused[ ] begin ioverflowmsg := ioverflowmsg+ inttostr( ); end; end; presults.add( ioverflowmsg ); exit; end; if pdigitsleft > 1 // because not descrementing pdigitsleft left though logically should begin := 0 pdigit begin addadigit( i, pdigitsleft - 1, inewsum, ppowers, idigitsused, presults, digitcount + 1 ); end; end else begin // lowest level if checkresult( psumsofar, idigitsused, digitcount + 1 ) 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 powwers presults.clear; ioverflow := false; imaxdigit := 0; := 0 9 begin fpowers[ ] := i; fused[ ] := 0; j := 2 pofsize begin fpowers[ ] := fpowers[ ] * i; if fpowers[ ] < 0 begin // overflow ioverflow := true; ioverflowmsg := 'overflowed while evaluating ' + inttostr( ) + '^' + inttostr( pofsize ); presults.add( ioverflowmsg ); break; end; end; if ioverflow begin break; end else begin imaxdigit := i; end; end; // have set our tabs , prepared not test digits // automatically give overflow if pparallel begin tparallel.&for( 1, imaxdigit, procedure(i : integer ) var isum : int64; begin istrings[ ] := tstringlist.create; isum := 0; addadigit( i, pofsize, isum, fpowers, fused, istrings[ ], 0 ); end); := 1 imaxdigit begin presults.addstrings( istrings[ ]); istrings[ ].free; end; end else begin := 1 imaxdigit 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 { doing here checking if psum contains same digits used create in first place. } idigitsused := digitsused; idigitcount := digitcount; isum := psum; while isum > 0 begin idigit := isum mod 10; isum := isum div 10; if idigitsused[ idigit ] > 0 begin dec( idigitsused[ idigit ]); dec( idigitcount ); end else begin result := false; exit; end; end; result := idigitcount = 0; end; end.
it interesting know how approach compares yours.
the result 19 digit numbers shown below:
(parallel)
Comments
Post a Comment