Hi Armando,
Okay, hopefully this satisfies your requirements, Mike:
Yes, this code seems to be viable in all the languages in question and it also makes Python a definitive winner in the interpreter race. Unfortunately it does seem to be sort of an overkill for John's SB.
But first things first. In order to have something to lean on against the background of your non-Windows MBC submission, I've cooked up a short C language script and compiled it with a -O3 switch using TDM GCC 4.3.3 (that's the fastest and most compact one I'm usually working with under Windows). Then I benchmarked it in the non-printing and printing modes against the Dynamic C and Dynamic Asm JIT compilers that are built in FBSL alongside its BASIC interpreter. Here are the scripts, and the respective timings can be seen in screenshots 1 and 2 below. Note that I've added the
limit variable to compute the pow() limit of inner for() loop only once, because otherwise it'll be recalculated again and again. This however shouldn't be necessary in BASICs because a standard BASIC must do it by definition.
C script:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>
int main()
{
int A, i, limit, gtc = GetTickCount();
for (A = 1; A <= 1000000; A++) {
if (A % 2 == 0 && A > 2) continue;
for (i = 3; i <= limit; i++)
if (A % i == 0) goto iterate;
// comment this out for non-printable version
iterate:;
}
printf("\nUptime: %.3f\n\nPress any key to continue...", (GetTickCount
() - gtc
) / 1000.0); return 0;
}
Dynamic C script:
#AppType Console
#Option Implicit
gtc = GetTickCount()
testC()
Print
Print "Uptime: ", (GetTickCount() - gtc) / 1000
Pause
DynC testC()
double pow(double, double);
void main()
{
int A, i, limit;
for (A = 1; A <= 1000000; A++) {
if (A % 2 == 0 && A > 2) continue;
limit
= pow(A
, 0.5) + 1; // avoid recalc in each iteration for (i = 3; i <= limit; i++)
if (A % i == 0) goto iterate;
// comment this out for non-printable version
iterate:;
}
}
End DynC
Dynamic Asm script:
#AppType Console
#Option Implicit
#DllImports msvcrt
gtc = GetTickCount()
testA()
Print
Print "Uptime: ", (GetTickCount() - gtc) / 1000
Pause
DynAsm testA()
.DATA
@format DB "%d", &HA, 0
@divisor DD 2
@exponent REAL8 0.5
.CODE
push ebx
mov ecx, 1 ; initialize A
nop ; 1-byte 1-clock alignment on dword boundary
.While ecx <= 1000000 ; A loop
mov eax, ecx
xor edx, edx
div DWORD PTR [divisor] ; get Mod in edx
.If edx = 0 .Then
.If ecx > 2 .Then
jmp iterate
.EndIf
.EndIf
push ecx ; store volatile register
push [exponent + 4] ; high dword of (double) exponent
push [exponent] ; low dword of (double) exponent
push 0 ; make room for high dword of (double) base
push ecx ; (int) base
fild DWORD PTR [esp] ; convert in-place to (double) base
fstp QWORD PTR [esp]
call pow ; call C function
add esp, 16 ; CDECL quirk
pop ecx ; restore volatile register
fistp DWORD PTR [esp - 4]
mov ebx, [esp - 4]
inc ebx ; initialize ebx with inner loop limit = pow(A, 0.5) + 1
mov edx, 3 ; initialize i
mov eax, eax ; 2-byte 1-clock alignment on dword boundary
.While edx <= ebx ; i loop
push edx ; save temporarily on stack
push ebx ; ditto
mov ebx, edx
xor edx, edx
mov eax, ecx
div ebx ; get Mod in edx
pop ebx ; restore from stack
.If edx = 0 .Then
pop edx ; ditto
jmp iterate
.EndIf
pop edx ; ditto
inc edx
.WEnd
; comment this out for non-printable version
push ecx ; store volatile register
Invoke printf, format, ecx ; call C function
add esp, 8 ; CDECL quirk
pop ecx ; restore volatile register
nop ; 1-byte 1-clock alignment on dword boundary
@iterate
inc ecx
.WEnd
pop ebx
ret
End DynAsm
The asm code isn't optimized in any particular way to keep closer to BASIC and C and it also uses Windows standard msvcrt.dll C runtime calls for compatibility with the prototype. I wish Charles could find some time to submit his OxygenBasic and assembly JIT versions too.
Then I benchmarked your Python code similarly against FBSL's and SB's BASIC interpreters, which showed that Python
is a winner given this particular scripting solution. Here are the scripts, and the corresponding non-printable and printable results are presented in screenshots 3 and 4 below.
Python 2 script:
for A in xrange(1, 1000000):
if A % 2 == 0 and A > 2: continue
for i in xrange(3, int(A**0.5) + 1):
if A % i == 0: break
# comment this out for non-printable version
else: print A
FBSL script:
#AppType Console
#Option Implicit
gtc = GetTickCount()
For A = 1 To 1000000
If A Mod 2 = 0 And A > 2 Then Continue
For i = 3 To A ^ 0.5 + 1
If A Mod i = 0 Then Continue Level 2
Next
' comment this out for non-printable version
Print A
Next
Print
Print "Uptime: ", (GetTickCount() - gtc) / 1000
Pause
Script BASIC script:
FOR A = 1 TO 1000000
IF A % 2 = 0 AND A > 2 THEN GOTO Iterate
FOR i = 3 TO A ^ 0.5 + 1
IF A % i = 0 THEN GOTO Iterate
NEXT
' comment this out for non-printable version
PRINT A, "\n"
Iterate:
NEXT
PRINTNL