program Magnanimous; //Magnanimous Numbers //algorithm find only numbers where all digits are even except the last //or where all digits are odd except the last //so 1,11,20,101,1001 will not be found //starting at 100001 "1>"+x"0"+"1" is not prime because of 1001 not prime {$IFDEF FPC} {$MODE DELPHI} {$Optimization ON} {$CODEALIGN proc=16} {$ELSE} {$APPTYPE CONSOLE} {$ENDIF} {$DEFINE USE_GMP} uses //strUtils, // commatize Numb2USA {$IFDEF USE_GMP}gmp,{$ENDIF} SysUtils; const MaxLimit = 10*1000*1000 +10; MAXHIGHIDX = 10; type tprimes = array of byte; tBaseType = Byte; tpBaseType = pByte; tBase =array[0..15] of tBaseType; tNumType = NativeUint; tSplitNum = array[0..15] of tNumType; tMagList = array[0..1023] of Uint64; var {$ALIGN 32} MagList : tMagList; dgtBase5, // count in Base 5 dgtORMask, //Mark of used digit (or (1 shl Digit )) dgtEvenBase10, dgtOddBase10: tbase; primes : tprimes; {$IFDEF USE_GMP} z : mpz_t;gmp_count :NativeUint;{$ENDIF} pPrimes0 : pByte; T0: int64; HighIdx,num,MagIdx,count,cnt: NativeUint; procedure InitPrimes; const smallprimes :array[0..5] of byte = (2,3,5,7,11,13); var pPrimes : pByte; p,i,j,l : NativeUint; begin l := 1; for j := 0 to High(smallprimes) do l*= smallprimes[j]; //scale primelimit to be multiple of l i :=((MaxLimit-1) DIV l+1)*l+1;//+1 should suffice setlength(primes,i); pPrimes := @primes[0]; for j := 0 to High(smallprimes) do begin p := smallprimes[j]; i := p; if j <> 0 then p +=p; while i <= l do begin pPrimes[i] := 1; inc(i,p) end; end; //turn the prime wheel for p := length(primes) div l -1 downto 1 do move(pPrimes[1],pPrimes[p*l+1],l); l := High(primes); //reinsert smallprimes for j := 0 to High(smallprimes) do pPrimes[smallprimes[j]] := 0; pPrimes[1]:=1; pPrimes[0]:=1; p := smallprimes[High(smallprimes)]; repeat repeat inc(p) until pPrimes[p] = 0; j := l div p; while (pPrimes[j]<> 0) AND (j>=p) do dec(j); if j
0) AND (j>=p) do begin dec(j,i); i := 6-i; end; if j
= Left) and (pMag[j] > Pivot) do begin pMag[j+1]:=pMag[j]; Dec(j); end; pMag[j+1]:= pivot; end; end; procedure OutBase5; var pb: tpBaseType; i : NativeUint; begin write(count :10); pb:= @dgtBase5[0]; for i := HighIdx downto 0 do write(pb[i]:3); write(' : ' ); pb:= @dgtORMask[0]; for i := HighIdx downto 0 do write(pb[i]:3); end; function Base10toNum(var dgtBase10: tBase):NativeUint; var i : NativeInt; begin Result := 0; for i := HighIdx downto 0 do Result := Result * 10 + dgtBase10[i]; end; procedure OutSol(cnt:Uint64); begin writeln(MagIdx:4,cnt:13,Base10toNum(dgtOddBase10):20, (Gettickcount64-T0) / 1000: 10: 3, ' s'); end; procedure CnvEvenBase10(lastIdx:NativeInt); var pdgt : tpBaseType; idx: nativeint; begin pDgt := @dgtEvenBase10[0]; for idx := lastIdx downto 1 do pDgt[idx] := 2 * dgtBase5[idx]; pDgt[0] := 2 * dgtBase5[0]+1; end; procedure CnvOddBase10(lastIdx:NativeInt); var pdgt : tpBaseType; idx: nativeint; begin pDgt := @dgtOddBase10[0]; //make all odd for idx := lastIdx downto 1 do pDgt[idx] := 2 * dgtBase5[idx] + 1; //but the lowest even pDgt[0] := 2 * dgtBase5[0]; end; function IncDgtBase5:NativeUint; // increment n base 5 until resulting sum of split number // can't end in 5 var pb: tpBaseType; n,i: nativeint; begin result := 0; repeat repeat //increment Base5 pb:= @dgtBase5[0]; i := 0; repeat n := pb[i] + 1; if n < 5 then begin pb[i] := n; break; end; pb[i] := 0; Inc(i); until False; if HighIdx < i then begin HighIdx := i; pb[i] := 0; end; if result < i then result := i; n := dgtORMask[i+1]; while i >= 0 do begin n := n OR (1 shl pb[i]); dgtORMask[i]:= n; if n = 31 then break; dec(i); end; if HighIdx<4 then break; if (n <> 31) OR (i=0) then break; //Now there are all digits are used at digit i ( not in last pos) //this will always lead to a number ending in 5-> not prime //so going on with a number that will change the used below i to highest digit //to create an overflow of the next number, to change the digits dec(i); repeat pb[i] := 4; dgtORMask[i]:= 31; dec(i); until i < 0; until false; if HighIdx<4 then break; n := dgtORMask[1]; //ending in 5. base10(base5) for odd 1+4(0,2),3+2(1,1),5+0(2,0) i := pb[0]; if i <= 2 then begin i := 1 shl (2-i); end else Begin //ending in 5 7+8(3,4),9+6(4,3) i := 1 shl (4-i); n := n shr 3; end; if (i AND n) = 0 then BREAK; until false; end; procedure CheckMagn(var dgtBase10: tBase); //split number into sum of all "partitions" of digits //check if sum is always prime //1234 -> 1+234,12+34 ;123+4 var LowSplitNum : tSplitNum; i,fac,n: NativeInt; isMagn : boolean; Begin n := 0; fac := 1; For i := 0 to HighIdx-1 do begin n := fac*dgtBase10[i]+n; fac *=10; LowSplitNum[HighIdx-1-i] := n; end; n := 0; fac := HighIdx; isMagn := true; For i := 0 to fac-1 do begin //n = HighSplitNum[i] n := n*10+dgtBase10[fac-i]; LowSplitNum[i] += n; if LowSplitNum[i]<=MAXLIMIT then begin isMagn := isMagn AND (pPrimes0[LowSplitNum[i]] = 0); if NOT(isMagn) then EXIT; end; end; {$IFDEF USE_GMP} For i := 0 to fac-1 do begin n := LowSplitNum[i]; if n >MAXLIMIT then Begin // IF NOT((n mod 30) in [1,7,11,13,17,19,23,29]) then EXIT; mpz_set_ui(z,n); gmp_count +=1; isMagn := isMagn AND (mpz_probab_prime_p(z,1) >0); if NOT(isMagn) then EXIT; end; end; {$ENDIF} //insert magnanimous numbers num := Base10toNum(dgtBase10); MagList[MagIdx] := num; inc(MagIdx); end; function Run(StartDgtCount:byte):Uint64; var lastIdx: NativeInt; begin result := 0; HighIdx := StartDgtCount;// 7 start with 7 digits LastIdx := HighIdx; repeat if dgtBase5[HighIdx] <> 0 then Begin CnvEvenBase10(LastIdx); CheckMagn(dgtEvenBase10); end; CnvOddBase10(LastIdx); CheckMagn(dgtOddBase10); inc(result); //output for still running every 16.22 Mio IF result AND (1 shl 22-1) = 0 then OutSol(result); lastIdx := IncDgtBase5; until HighIdx > MAXHIGHIDX; end; BEGIN {$IFDEF USE_GMP}mpz_init_set_ui(z,0);{$ENDIF} T0 := Gettickcount64; InitPrimes; T0 -= Gettickcount64; writeln('getting primes ',-T0 / 1000: 0: 3, ' s'); T0 := Gettickcount64; fillchar(dgtBase5,SizeOf(dgtBase5),#0); fillchar(dgtEvenBase10,SizeOf(dgtEvenBase10),#0); fillchar(dgtOddBase10,SizeOf(dgtOddBase10),#0); //Magnanimous Numbers that can not be found by this algorithm MagIdx := 0; MagList[MagIdx] := 1;inc(MagIdx); MagList[MagIdx] := 11;inc(MagIdx); MagList[MagIdx] := 20;inc(MagIdx); MagList[MagIdx] := 101;inc(MagIdx); MagList[MagIdx] := 1001;inc(MagIdx); //cant be checked easy for ending in 5 MagList[MagIdx] := 40001;inc(MagIdx); {$IFDEF USE_GMP} mpz_init_set_ui(z,0);{$ENDIF} count := Run(0); writeln; CnvOddBase10(highIdx); writeln(MagIdx:5,count:12,Base10toNum(dgtOddBase10):18, (Gettickcount64-T0) / 1000: 10: 3, ' s'); InsertSort(@MagList[0],0,MagIdx-1); {$IFDEF USE_GMP} mpz_clear(z);writeln('Count of gmp tests ',gmp_count);{$ENDIF} For cnt := 0 to MagIdx-1 do writeln(cnt+1:3,' ',MagList[cnt]); {$IFDEF WINDOWS} readln; {$ENDIF} end.