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:

non parallel

(non parallel) , parallel

(parallel)


Comments

Popular posts from this blog

java - SSE Emitter : Manage timeouts and complete() -

jquery - uncaught exception: DataTables Editor - remote hosting of code not allowed -

java - How to resolve error - package com.squareup.okhttp3 doesn't exist? -