BrowserUk has asked for the wisdom of the Perl Monks concerning the following question:

Given a size, S, that is some multiple of P=4096; and record size R; find the largest common multiple of R & P < S.

Eg. S = 2GB = 2147483648; R = 12; LCM of 12 & 4096 < 2147483648 = 2147475456.

Easy to find iteratively:

$R = 12; $S = 2*1024**3; $c -= 4096 while $c % $r; print $c;; 2147475456

But it can be calculated right? (Long day; brain not cooperating.)

Note: P is always 4096; R can be larger or smaller than 4096; S will always be a multiple of P, and usually a multiple of 1GB.

Eg2. S = 3GB = 3221225472; R = 5007; LCM of 5007 & 4096 < 3221225472 = 3219861504.


With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

Replies are listed 'Best First'.
Re: Simple arithmetic?
by oiskuu (Hermit) on Mar 08, 2015 at 11:15 UTC

    Using bog standard LCM:

    my @T = ( [2147483648, 12, 4096], [3221225472, 5007, 4096], [4096, 4096, 4096], [8192, 8192, 4096], [15000, 8192, 4096], [17000, 8192, 4096], [17000, 10, 4096], ); sub gcd { !$_[1] ? $_[0] : gcd($_[1], $_[0] % $_[1]) } sub lcm { $_[0] * $_[1] / gcd($_[0], $_[1]) } for (@T) { my ($S, $R, $P) = @$_; my $N = $S - $S % lcm($R, $P); print "@$_: $N\n"; }

      Using bog standard LCM

      That's a very clean, and totally generic implementation. Thank you.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
Re: Simple arithmetic?
by Laurent_R (Canon) on Mar 07, 2015 at 22:27 UTC
    I would first determine the least common multiple (LCM) of R and P, which is almost entry level algorithmic. Then divide S by the LCM, and multiply the LCM by the integer part of the result of that division.

    Je suis Charlie.
      Too late, forget about it...

      Exactly, and one can also utilize the fact that 4096 is a power of 2:

      $lcm = $r * 4096; $lcm /= 2 until $lcm % 8192; $c = int( $s/$lcm) * $lcm;

      UPDATE: 7 hours of sleep later, here is what I wanted to say, but Anonymous Monk has posted it already in node 1119206.

      use strict; use warnings; my $s = 3221225472; my $r = 5007; my $lcm = $r; my $m = 0; $lcm/=2 while 12>$m++ and !($lcm%2); $lcm *= 4096; my $c = int( $s/$lcm ) * $lcm; print "$c\n";
        and one can also utilize the fact that 4096 is a power of 2

        That's a really useful insight. It makes deriving the lcm substantially more efficient; especially for large values of S combined with R=prime. Thank you.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
        In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
      I would first determine the least common multiple (LCM) of R and P, which is almost entry level algorithmic. Then divide S by the LCM, and multiply the LCM by the integer part of the result of that division.

      That's effectively, exactly what I was doing, but in my sleep-deprived state, I was convinced that I could avoid the iteration and calculate the result directly, despite that I couldn't see how. Hence my question. Thank you.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
Re: Simple arithmetic?
by Anonymous Monk on Mar 08, 2015 at 04:43 UTC
    Inspired by previous answers. As usual, the absence of bugs is totally not guaranteed :) But should be something like that...
    use strict; use warnings; # greatest common multiple sub gcm { my ( $max, $num ) = @_; for ( my $c = 1; ( $num & 1 ) == 0 && $c < 4096; $c <<= 1 ) { $num >>= 1; } my $lcm = 4096 * $num; # least common multiple return int( $max / $lcm ) * $lcm; } sub pretty { return shift =~ s/\d \K (?= (?: \d{3} )+ \z)/_/xgr; } print pretty( gcm( 2_147_483_648, 12 ) ), "\n"; print pretty( gcm( 3_221_225_472, 5007 ) ), "\n"; print pretty( gcm( 4_096, 4_096 ) ), "\n"; print pretty( gcm( 8_192, 8_192 ) ), "\n"; print pretty( gcm( 15_000, 8_192 ) ), "\n"; print pretty( gcm( 17_000, 8_192 ) ), "\n"; print pretty( gcm( 17_000, 10 ) ), "\n";
    output:
    2_147_475_456 3_219_861_504 4_096 8_192 8_192 16_384 0
      Inspired by previous answers.

      I like your way of incorporating hdb's powers-of-two observation into the GCD() calculation.

      the absence of bugs is totally not guaranteed

      Understood. It's my responsibility to test code I use.

      It stands up to all the likely scenarios (for my application) that I've tested. Thank you.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

        Of course, my post came later, so the observation is this Anonymus Monk's own original observation. If in addition, as you comment above, R is prime (different from 2) or only odd, then the LCM is always 4096*R, so the whole discussion redundant...

Re: Simple arithmetic? (And the winner is ... )
by BrowserUk (Patriarch) on Mar 08, 2015 at 17:44 UTC

    By an almost unbelievable margin of being 300 million times faster: oiskuu's implementation from Anonymonk's implementation:

    C:\test\C>gcm 3221225472 anonyM: gcm for s=3221225472 & r=1 to 1610612736 took:13.076620219 oiskuu: gcm for s=3221225472 & r=1 to 1610612736 took: 0.000000041

    (And yes. I've verified the results. Otherwise I would have posted this hours ago.)

    It all comes down to the extreme optimisability of the tail-recursive Euclidean gcd algorithm, which converges very, very fast.

    The benchmark code (uncomment the comments for verification ):

    #include <stdio.h> #include <stdlib.h> #include "mytypes.h" U64 gcd( U64 a, U64 b ) { return !b ? a : gcd( b, a % b ); } U64 lcm( U64 a, U64 b ) { return a * b / gcd( a, b ); } U64 gcm( U64 max, U64 n ) { U64 c, lcm; for( c = 1; ( ~n & 1 ) && ( c < 4096 ); c <<= 1 ) n >>= 1; lcm = n * 4096; return ( max / lcm ) * lcm; } #define GB ( 1024ull * 1024ull * 1024ull ) #define PAGE 4096 void main( int argc, char **argv ) { U64 s = argc > 1 ? _atoi64( argv[ 1 ] ) : 2*GB; U64 r, start, end, gsm; // U64 *res = malloc( sizeof(U64) * (s>>1) ); start = __rdtsc(); for( r = 1; r < ( s >> 1 ); ++r ) { // res[ r ] = gsm = gcm( s, r ); } end = __rdtsc(); printf( "anonyM: gcm for s=%I64u & r=1 to %I64u took:%.9f\n", s, s +>>1, (double)( end - start ) / 2394046359.0 ); start = __rdtsc(); for( r = 1; r < ( s >> 1 ); ++r ) { // if( res[ r ] != ( gsm = s - ( s % lcm( r, 4096 ) ) ) // ) printf( "%I64u != %I64u\n", gsm, res[ r ] ) ; } end = __rdtsc(); printf( "oiskuu: gcm for s=%I64u & r=1 to %I64u took:%.9f\n", s, s +>>1, (double)( end - start ) / 2394046359.0 ); return; }

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

      "I wuz in ur um-puter, eating ur loopz."

      I don't know how MSVC handles things, but generally there are other ways to prevent unwanted benchmark optimizations. Using volatile is almost never necessary, and very often has different implications to what was intended. Just one example, quoting gcc.info:

      Accesses to non-volatile objects are not ordered with respect to volatile accesses. You cannot use a volatile object as a memory barrier to order a sequence of writes to non-volatile memory.

      Usually, a barrier of some sort is indicated. With gcc/icc/clang, the following optimization barrier should work:

      #define barrier() asm volatile("": : :"memory")
      (Here the volatile may be due to some compiler bugs.)

      The ways to prevent a compiler of being too smart:

      • Put the test routine(s) in separate files ("compilation units"), link together. But nowadays we can have link time optimization (-flto), so care must be taken (incremental linking for those parts that want lto).
      • Mark your test routines with __attribute__((__noinline__)), so they don't get inlined. Result should be similar to having them in separate units. However, this does NOT prevent e.g. clang determining that the function is a nop, and optimizing it out!
      • Use optimization barrier(s) in the loop and/or test routine. This will make sure the loop stays, even if the body is a nop. Barrier in the test routine might be necessary, lest the compiler discover and hoist a "const" function.
      • Have the main loop calculate some sort of result. In other words, the program as a whole needs to have a side effect. E.g. if the test routine returns int, one might compute a checksum and print that in the end; will also serve as verification.
      So, probably it's best to use both noinline attribute and an optimization barrier.

      Now, getting back to the original topic. Lcm with 4096 means simply to have twelve zeroes at the end. I'd code it like this:

      $n <<= 1 while $n & 0xfff;
      (Counting trailing zeroes can also be optimized. Some x86 (Haswell) have an instruction for that. Wikipedia links to Bit Twiddling Hacks; there are other sites and books on the topic.)

      Update: added the 4th clause to above list.

        So, probably it's for the best to use both noinline attribute and an optimization barrier.

        The problem is that nothing I do inside the function, whether inlined or not, will prevent the compiler optimising the loop away. The decision is, (appears to be), that because the variable to which the result of the function is assigned is never used outside the loop, and the function has no side effects, the loop is redundant. (Though I haven't worked out why the second loop isn't optimised away for similar reasons.

        The use of volatile on that variable works because the compiler cannot decide that the value is never used. Whilst volatile can have other effects upon the code generated, these mostly relate to multi-threaded code which is not in play here. Also, the MS compiler has extended guarantees with regard to volatile (on non-ARM systems):

        /volatile:ms

        Selects Microsoft extended volatile semantics, which add memory ordering guarantees beyond the ISO-standard C++ language. Acquire/release semantics are guaranteed on volatile accesses. However, this option also forces the compiler to generate hardware memory barriers, which might add significant overhead on ARM and other weak memory-ordering architectures. If the compiler targets any platform except ARM, this is default interpretation of volatile.

        Conversely, the read/write/ReadWrite/Barrier intrinsics are now deprecated:

        The _ReadBarrier, _WriteBarrier, and _ReadWriteBarrier compiler intrinsics and the MemoryBarrier macro are all deprecated and should not be used. For inter-thread communication, use mechanisms such as atomic_thread_fence and std::atomic<T>, which are defined in the C++ Standard Library Reference. For hardware access, use the /volatile:iso compiler option together with the volatile (C++) keyword.

        The volatile keyword also seems to impose lesser, but enough, constraints. (That's an interpretation, rather than an MS stated fact.)

        Now, getting back to the original topic. Lcm with 4096 means simply to have twelve zeroes at the end. I'd code it like this:
        $n <<= 1 while $n & 0xfff;

        Update:

        Um. That code doubles $n whilst it's lower than 4096; the original code calls for halving it; at most 12 times?

        And if I just switched the shift direction, an input $n of 0xffffffffff; would be reduced to 0 before the loop terminated.

        Ignore the above, I left the lcm = n * 40096; in, where (I assume) you meant to replace:

        for( c = 1; ( ~n & 1 ) && ( c < 4096 ); c <<= 1 ) n >>= 1; lcm = n * 4096;

        With:

        while( n & 0xfff ) n <<= 1; lcm = n;

        Which works, but takes twice as long as the original the original version:

        C:\test\C>gcm gcm : 2132901888 gcm2: 2132901888 gcm3: 2132901888 anonyM: gcm for s=2147483648 & r=1 to 1073741824 took:33.850023994460 anonyM: gcm2 for s=2147483648 & r=1 to 1073741824 took:46.293298113614 anonyM: gcm3 for s=2147483648 & r=1 to 1073741824 took:64.208097030422

        /Update:

        (Counting trailing zeroes can also be optimized.)

        I thought about that last night and tried using the __BitScanForward64() intrinsic:

        U64 gcm2( U64 max, U64 n ) { U32 b; U64 c, lcm; _BitScanForward64( &b, n ); n >>= min( b, 12 ); lcm = n * 4096; return ( max / lcm ) * lcm; }

        Which looked like it should be more efficient, compiling to this:

        Rather than this:

        But the reality turns out to be disappointingly about 50% slower:

        C:\test\C>gcm anonyM: gcm for s=2147483648 & r=1 to 1073741824 took: 33.92063749171 +5 anonyM: gcm2 for s=2147483648 & r=1 to 1073741824 took: 46.15194765908 +9 oiskuu: gcm for s=2147483648 & r=1 to 1073741824 took:330.49201177311 +0

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
        In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

        FWIW: Of many things I've tried to improve on Anonymous Monk's gcm(), the only thing that has worked is this:

        U64 gcm4( U64 max, U64 n ) { U64 c, lcm; for( c = 1; ( ~n & 1 ) && ( c < 12 ); ++c ) n >>= 1; lcm = n * 4096; return ( max / lcm ) * lcm; }

        Incrementing seems to be fractionally faster than shifting:

        anonyM: gcm for s=2147483648 & r=1 to 1073741824 took:33.850345514550 + ### original anonyM: gcm4 for s=2147483648 & r=1 to 1073741824 took:33.590549831120 + ### my tweak

        But the difference, 1/4 second on > 1 billions calls is so minimal (0.2 nanoseconds), and the shifting better captures the semantics, I've stuck with the original.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
        In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

        And no sooner have I said that, and I think of a way to use _BitScanForward64() that improves upon the original by 70+%:

        C:\test\C>gcm anonyM: gcm for s=2147483648 & r=1 to 1073741824 took:8.535316994670 anonyM: gcm2 for s=2147483648 & r=1 to 1073741824 took:2.271266720696

        Pre-masking the scanned var, avoids the later subtraction being conditional:

        U64 gcm2( U64 max, U64 lcm ) { I32 b; _BitScanForward64( &b, lcm & 0xfff ); lcm <<= ( 12 - b ); return ( max / lcm ) * lcm; }

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
        In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
      Well that's a weird result BUK :) So I actually compiled your code (with some changes to make it suitable for gcc on linux). I was getting strange results too. 1500 nanoseconds for anonM algorithm, no matter what s was (at -O2). I'm curious why that happened. With some checksums to verify results the execution time became more realistic (with 1:10 bias towards bitshift stuff, but perhaps your compiler recognizes Euclid's algorithm? gcc 4.7 doesn't, it seems :) I don't know C very well, though (so here it is)

        Anonymonk's implementation by an order of magnitude over oiskuu's:

        C:\test\C>gcm anonyM: gcm for s=2147483648 & r=1 to 1073741824 took: 33.607916866993 + oiskuu: gcm for s=2147483648 & r=1 to 1073741824 took:329.551997991197

        Thanks for the sanity check AnonyMonk!

        And the difference between this benchmark and the previous (unbelievable) one? One keyword:

        void main( int argc, char **argv ) { U64 s = argc > 1 ? _atoi64( argv[ 1 ] ) : 2*GB; U64 r, start, end; U64 volatile gsm; // ^^^^^^^^ *** Prevent the co +mpiler from optimising the loop away in its entirety *** D'oh! start = __rdtsc(); for( r = 1; r < ( s >> 1 ); ++r ) { gsm = gcm( s, r ); } end = __rdtsc(); printf( "anonyM: gcm for s=%I64u & r=1 to %I64u took:%.12f [%I64u] +\n", s, s>>1, (double)( end - start ) / 2394046359.0 ); start = __rdtsc(); for( r = 1; r < ( s >> 1 ); ++r ) { gsm = s - ( s % lcm( r, 4096 ) ); } end = __rdtsc(); printf( "oiskuu: gcm for s=%I64u & r=1 to %I64u took:%.12f [%I64u] +\n", s, s>>1, (double)( end - start ) / 2394046359.0 ); return; }

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
        In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
        Well that's a weird result BUK :) So I actually compiled your code (with some changes to make it suitable for gcc on linux). I was getting strange results too. 1500 nanoseconds for anonM algorithm, no matter what s was (at -O2). I'm curious why that happened. With some checksums to verify results the execution time became more realistic (with 1:10 bias towards bitshift stuff,

        I understand your reaction. I had the same. I spent 4 hours trying to find something amiss. I failed.

        If you look at the commented out verification code in what I posted above (with extra comments):

        void main( int argc, char **argv ) { U64 s = argc > 1 ? _atoi64( argv[ 1 ] ) : 2*GB; U64 r, start, end, gsm; // U64 *res = malloc( sizeof(U64) * (s>>1) ); + //// An array to store every result from loop 1 (anonyM) start = __rdtsc(); for( r = 1; r < ( s >> 1 ); ++r ) { // res[ r ] = + //// Assign the result to the array gsm = gcm( s, r ); } end = __rdtsc(); printf( "anonyM: gcm for s=%I64u & r=1 to %I64u took:%.9f\n", s, s +>>1, (double)( end - start ) / 2394046359.0 ); start = __rdtsc(); for( r = 1; r < ( s >> 1 ); ++r ) { // if( res[ r ] != + //// If the result from the first loop, doesn't match the result fro +m this loop ( gsm = s - ( s % lcm( r, 4096 ) ) ) // ) printf( "%I64u != %I64u\n", gsm, res[ r ] ) + ///// Yell about it. ; } end = __rdtsc(); printf( "oiskuu: gcm for s=%I64u & r=1 to %I64u took:%.9f\n", s, s +>>1, (double)( end - start ) / 2394046359.0 ); return; }

        Of course, the additional code slows things down and changes the timing completely, but not a single mismatch is found.

        I can't think of a more comprehensive way to verify the algorithms than to directly compare their results for a full range of inputs?

        but perhaps your compiler recognizes Euclid's algorithm?

        I'll admit that I do not understand quite what the optimiser has done to the code.

        The Euclidean gcd() function is pretty easy to recognise in the assembler output:

        _TEXT SEGMENT a$ = 48 b$ = 56 gcd PROC ; 5 : U64 gcd( U64 a, U64 b ) { ; a in rcx, b +in rdx $LN5: sub rsp, 40 ; reserve some stack space mov r8, rdx ; put a copy of b i +n r8 ; 6 : return !b ? a : gcd( b, a % b ); mov rax, rcx ; put a in rax (res +ult register) test rdx, rdx ; test b je SHORT $LN4@gcd ; jump to return if +it is 0; ie. if b=0 return a xor edx, edx ; empty rdx ready f +or div mov rcx, r8 ; move b into rcx ( + ie. b becomes a for recursive call ) div r8 ; divide rdx:rax (0 +:a) by r8 (b); leaves quotient in rax, the remainder (modulus) in rdx + (thus b in the recursive call) call gcd ; recurse $LN4@gcd: ; result is in + rax. ; 7 : } add rsp, 40 ; clean up the stack ret 0 ; return popping 0 +bytes from the stack gcd ENDP _TEXT ENDS

        Which is well and good, but the the code in the loop that (should be) calling this function is very confusing

        Realisation dawns!

        Without the verification code, the compiler recognises that the value calculated within the loop is never used outside of it, and simply optimises the entire loop away:

        ; 35 : start = __rdtsc(); rdtsc shl rdx, 32 ; 00000020H or rax, rdx mov rcx, rax ; 36 : for( r = 1; r < ( s >> 1 ); ++r ) { ; 37 : ( gsm = s - ( s % lcm( r, 4096 ) ) ); ; 38 : } ; 39 : end = __rdtsc(); rdtsc shl rdx, 32 ; 00000020H

        In other words, the times output are the time it takes to make two calls to _rdtsc().


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
        In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked
        _
Re: Simple arithmetic?
by cheako (Beadle) on Mar 07, 2015 at 22:17 UTC

    We are talking about integer factorisation?! Can't be calculated without a quantum computer.

    Plus your code could endless loop.
    $c -= 4096 while $c % $r && $c > 0;

    One good solution is to use a lookup table.

    use Fcntl; # For O_RDWR, O_CREAT, etc. use SDBM_File; # 0666 reduced by umask. tie my%__intfactor, 'SDBM_File','/var/tmp/intfactor.sdbm', O_RDWR|O_CREAT, 0666) or { warn"Couldn't tie SDBM file '/var/tmp/intfactor.sdbm': $!"; warn"continuing with ramdb"; }; sub intfactor() { exists $__intfactor{%r} and return $__intfactor{%r}; $c -= 4096 while $c % $r; return $__intfactor{%r}=$c; } # I'm lost by the meaning of your code, where is $s used? $r = 12; $s = 2*1024**3; print intfactor($c,$r);

    Further optimizations can be made with a better search pattern:
    http://en.wikipedia.org/wiki/Least_common_multiple

      It would be a good idea to take the time to read and understand PerlMonks for the Absolute Beginner and How do I post a question effectively?. Please mark updates to posts, you've made radical changes/additions to various posts without doing this, perhaps as a way of having the first response before actually having a valid reply. Perhaps this stems back to how you've interpreted some of the responses to PM Leveling Guide.. I'm still not clear on why you feel the need accelerate leveling. The indirect responses to your leveling thread are worth further consideration on this subject.

        Still, hdb is right.

        You would be friendlier with a beginner (who just forgot marking an update), without this inappropriate outburst of a regular (who indeed should know better).

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)

        PS: Je suis Charlie!

      I down voted this post last night when you posted the first three lines of the current post:

      We are talking about integer factorisation?

      This has (almost) nothing to do with integer factorisation. That is to say, whilst there might be an approach the problem using integer factorisation; it would be like using calculus to tally your bar bill.

      Can't be calculated without a quantum computer.

      Whilst generalised integer factorisation is known to be hard; for the size of integers involved here < 2^64, there are simple, efficient methods available.

      Plus your code could endless loop

      You're right, it could; but only if the product, $r *4096 > $c; which will never be the case; and the 'cure' (omitted for clarity in the description of the question) is trivial.

      So now we come to your belatedendum:

      One good solution is to use a lookup table.

      (Apart from: what does $__intfactor{%r} mean?, (which I'll assume is a typo); and where did $r and $c come from in that subroutine? (Which I'll assume is just laziness.)

      Offering a solution that caches to disk, the results of the iterative method I posted, doesn't begin to answer the question I asked.

      It's like answering the question "How do we solve world hunger", with a proposal for setting up food warehouses and suggesting that when people are hungry, they simply go to the warehouse and collect some food.

      Finally

      This is the third time in the last couple of days where you've immediately posted something fairly meaningless when a SoPW first appears; and then silently expanded/modified it without attribution later. Apparently taking Ambrus' "advice" to heart.

      Fair warning: Continue to do so in threads I start, or those I am interested in, and you and I will have a problem.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
      In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

        I find your response far too harsh and not really appropriate, generally and for this forum in particular. Especially in the light of the fact, that your posted snippet is far from exact:

        $R = 12; $S = 2*1024**3; $c -= 4096 while $c % $r;

        You use upper and lower case $r, $c is not initialized, so the while-loop will terminate immediately.