HP Forums

Full Version: Benchmark: Savage
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
An implementation of the Savage benchmark, in PPL and CAS:
Update: And now in Python-syntax-in-CAS too.
Code:


 //Benchmark: Savage 
 //PPL V0.1 

 //OMITTED: "RAD" in the original

 EXPORT A_SAVAGE()
 BEGIN
  LOCAL AA;
  AA:=1;
  FOR I FROM 1 TO 2499 DO
    AA:=TAN(ATAN(EXP(LN(√(AA*AA)))))+1
  END;
  RETURN AA;
 END;

#CAS
 A_SavageCAS1(f):=
 BEGIN
  LOCAL aa;
  aa:=1;
  FOR I FROM 1 TO 2499 DO
    aa:=TAN(ATAN(EXP(LN(√(aa*aa)))))+1
  END;
  RETURN (aa);
 END;
#END

 A_SavageCAS2()
 BEGIN
  LOCAL aa;
  aa:=1;
  FOR I FROM 1 TO 2499 DO
    aa:=CAS(TAN(ATAN(EXP(LN(√(aa*aa))))))+1;
  END;
  RETURN (aa);
 END;

 RRR(RR)
 //REPORT RESULT,RELATIVE ERROR
 BEGIN
  RETURN {RR,((2500-RR)/2500)};
 END;

 EXPORT SAVAGE()
 BEGIN
  LOCAL RR;
  PRINT();
  PRINT("Savage Benchmark");
  PRINT({" PPL1: ",TEVAL(RR:=A_SAVAGE()),RRR(RR)});
  PRINT({" CAS1: ",TEVAL(RR:=A_SavageCAS1("")),RRR(RR)});
 
  PRINT({" CAS2: ",TEVAL(RR:=A_SavageCAS2()),RRR(RR)});

 //RETURN {TEVAL(RR:=SAVAGED()),RR,TEVAL(RR:=SAVAGEDCAS()),RRR(RR)};
 END;
Version 0.2

Code:


 //Benchmark: Savage 
 //PPL V0.2 

 //OMITTED: "RAD" in the original
 LOCAL AA;

 EXPORT A_SavagePPL()
 BEGIN
  LOCAL AA;
  AA:=1;
  FOR I FROM 1 TO 2499 DO
    AA:=TAN(ATAN(EXP(LN(√(AA*AA)))))+1
  END;
  RETURN AA;
 END;

 MLFOR ()
 BEGIN
  //LOCAL AA;
  RETURN AA:=TAN(ATAN(EXP(LN(√(AA*AA)))))+1;
 END;
 
 EXPORT A_SavageMAKE()
 BEGIN
  //LOCAL AA;
  AA:=1;
  MAKELIST(MLFOR(),AA,1,2499);
  RETURN AA;
 END;

#CAS
 A_SavageCAS1(f):=
 BEGIN
  LOCAL aa;
  aa:=1;
  FOR I FROM 1 TO 2499 DO
    aa:=TAN(ATAN(EXP(LN(√(aa*aa)))))+1
  END;
  RETURN (aa);
 END;
#END

 A_SavageCAS2()
 BEGIN
  LOCAL aa;
  aa:=1;
  FOR I FROM 1 TO 2499 DO
    aa:=CAS(TAN(ATAN(EXP(LN(√(aa*aa))))))+1;
  END;
  RETURN (aa);
 END;

 RRR(RR)
 //REPORT RESULT,RELATIVE ERROR
 BEGIN
  RETURN {RR,((2500-RR)/2500)};
 END;

 //APPROX:
 //I FIND NO CLEAR WINNER BETWEEN PPL AND MAKE.
 //EXACT:
 //I FIND CAS2 CONSISTENTLY FASTER THAN CAS1

 EXPORT SAVAGE()
 BEGIN
  LOCAL RR;
  PRINT();
  PRINT("Savage Benchmark");
  PRINT({" PPL1: ",TEVAL(RR:=A_SavagePPL()),RRR(RR)});
  PRINT({" MAKE: ",TEVAL(RR:=A_SavageMAKE()),RRR(RR)});
 
  PRINT({" CAS1: ",TEVAL(RR:=A_SavageCAS1("")),RRR(RR)});
  PRINT({" CAS2: ",TEVAL(RR:=A_SavageCAS2()),RRR(RR)});
  
 END;
Anders, thank you for reporting timings for this benchmark on the Prime C and Prime G2.
http://www.hpmuseum.org/forum/thread-11202-page-3.html
Version 0.3 Beta adds an implementation of the Savage benchmark using Python-syntax-in-CAS.

That specific implementation is less accurate than the PPL version, hence the Beta release in case I have mis-coded something.
Other timings should be unaffected.

Code:

//Benchmark: Savage 
 LOCAL CRID:="Savage Benchmark (Prime) V0.3 Beta"; 
 //Beta in respect of Pythonesque results

 //OMITTED: "RAD" in the original:
 //User must select Radians

 LOCAL AA;

 EXPORT SavagePPL()
 BEGIN
  LOCAL AA;
  AA:=1;
  FOR I FROM 1 TO 2499 DO
    AA:=TAN(ATAN(EXP(LN(√(AA*AA)))))+1
  END;
  RETURN AA;
 END;

 MLFOR ()
 BEGIN
  //LOCAL AA;
  RETURN AA:=TAN(ATAN(EXP(LN(√(AA*AA)))))+1;
 END;
 
 EXPORT SavageMAKE()
 BEGIN
  //LOCAL AA;
  AA:=1;
  MAKELIST(MLFOR(),AA,1,2499);
  RETURN AA;
 END;

#CAS
 SavageCAS1(f):=
 BEGIN
  LOCAL aa;
  aa:=1;
  FOR I FROM 1 TO 2499 DO
    aa:=TAN(ATAN(EXP(LN(√(aa*aa)))))+1
  END;
  RETURN (aa);
 END;

def savagepysyn() :
   local ii,aa
   aa=1
   for ii in range(1,2499):
     #aa= tan(atan(exp(math.log(sqrt(aa*aa)))))+1
     aa= math.tan(math.atan(math.exp(math.log(math.sqrt(aa*aa)))))+1

#END

 SavageCAS2()
 BEGIN
  LOCAL aa;
  aa:=1;
  FOR I FROM 1 TO 2499 DO
    aa:=CAS(TAN(ATAN(EXP(LN(√(aa*aa))))))+1;
  END;
  RETURN (aa);
 END;

 RRR(RR)
 //REPORT RESULT,RELATIVE ERROR
 BEGIN
  RETURN {RR,((2500-RR)/2500)};
 END;

 //APPROX:
 //I FIND NO CLEAR WINNER BETWEEN PPL AND MAKE.
 //EXACT:
 //I FIND CAS2 CONSISTENTLY FASTER THAN CAS1

 EXPORT SAVAGE()
 BEGIN
  //LOCAL aa;
  LOCAL RR;
 
  PRINT();
  PRINT(CRID);
  PRINT({" PPL1  : ",TEVAL(RR:=SavagePPL()),RRR(RR)});
  PRINT({" MAKE  : ",TEVAL(RR:=SavageMAKE()),RRR(RR)});
 
  PRINT({" CAS1  : ",TEVAL(RR:=SavageCAS1("")),RRR(RR)});
  PRINT({" CAS2  : ",TEVAL(RR:=SavageCAS2()),RRR(RR)});
  PRINT({" PySyn : ",TEVAL(savagepysyn()),RRR(aa)});
  PRINT(CRID);
 END;

Update: Accuracy in Python solved...I had the range wrong...Corrected v0.4 follows.
Note that the Python-in-CAS code can affect indexing.
Version 0.4 adds a Python-syntax-in-CAS implementation.
This corrects the bug in my earlier beta version. Now, the accuracy SEEMS better than PPL, although since less bits are used in CAS floats I presume that is a fluke of these specific calculations (bits: see http://www.hpmuseum.org/forum/thread-11484.html)
The CAS2 procedure is now exported for improved visibility from the Run menu.

Removing the "math" references present in my V0.3Beta significantly improves timings.
Indeed, the Pythonesque timings now seem faster than the PPL version.
Code:

//Benchmark: Savage 
 LOCAL CRID:="Savage Benchmark (Prime) V0.4"; 

 //OMITTED: "RAD" in the original:
 //User must select Radians

 LOCAL AA;

 EXPORT SavagePPL()
 BEGIN
  LOCAL AA;
  AA:=1;
  FOR I FROM 1 TO 2499 DO
    AA:=TAN(ATAN(EXP(LN(√(AA*AA)))))+1
  END;
  RETURN AA;
 END;

 MLFOR ()
 BEGIN
  //LOCAL AA;
  RETURN AA:=TAN(ATAN(EXP(LN(√(AA*AA)))))+1;
 END;
 
 EXPORT SavageMAKE()
 BEGIN
  //LOCAL AA;
  AA:=1;
  MAKELIST(MLFOR(),AA,1,2499);
  RETURN AA;
 END;

#CAS
 SavageCAS1(f):=
 BEGIN
  LOCAL aa;
  aa:=1;
  FOR I FROM 1 TO 2499 DO
    aa:=TAN(ATAN(EXP(LN(√(aa*aa)))))+1
  END;
  RETURN (aa);
 END;

def savagepysyn() :
   local ii,aa
   aa=1
   for ii in range(1,2500):
     aa= tan(atan(exp(log(sqrt(aa*aa)))))+1
#END

 EXPORT SavageCAS2()
 BEGIN
  LOCAL aa;
  aa:=1;
  FOR I FROM 1 TO 2499 DO
    aa:=CAS(TAN(ATAN(EXP(LN(√(aa*aa))))))+1;
  END;
  RETURN (aa);
 END;

 RRR(RR)
 //REPORT RESULT,RELATIVE ERROR
 BEGIN
  RETURN {RR,((2500-RR)/2500)};
 END;

 //APPROX:
 //I FIND NO CLEAR WINNER BETWEEN PPL AND MAKE.
 //EXACT:
 //I FIND CAS2 CONSISTENTLY FASTER THAN CAS1

 EXPORT SAVAGE()
 BEGIN
  //LOCAL aa;
  LOCAL RR;
 
  PRINT();
  PRINT(CRID);
  PRINT({" PPL1  : ",TEVAL(RR:=SavagePPL()),RRR(RR)});
  PRINT({" MAKE  : ",TEVAL(RR:=SavageMAKE()),RRR(RR)});
 
  PRINT({" CAS1  : ",TEVAL(RR:=SavageCAS1("")),RRR(RR)});
  PRINT({" CAS2  : ",TEVAL(RR:=SavageCAS2()),RRR(RR)});
  PRINT({" PySyn : ",TEVAL(savagepysyn()),RRR(aa)});
  PRINT(CRID);
 END;
Update: See note regarding Python-in-CAS affecting indexing.
Hi, StephenG1CMZ

What to you mean by Python CAS float had less bits than PPL ?

Do you have some benchmark numbers ?

How does it compared to http://www.technicalc.org/tiplist/en/fil...ip6_50.pdf
In the other thread, Parisse said CAS floats had 48 bits not 53 for the mantissa.
I work on the Android version, so don't have any absolute timings, but the Pythonesque version seems about twice as fast as the PPL.

It's not the same as in your reference, in which the FOR loop is followed by a division by 2500, if I read it correctly.
I don't recall that in the original. (I do a similar calculation for relative error, but outside the timed code).
My benchmark is meant to implement the original Savage, apart from:
I don't change the mode to Radians (I don't like benchmarks that leave the device in a different mode than it started in)
And I wrap the original code in a procedure call, which wasn't in the original.
(09-30-2018 07:20 AM)StephenG1CMZ Wrote: [ -> ]Pythonesque version seems about twice as fast as the PPL.

That might explained why Python version is more accurate.

CAS float = 53 bits double, truncated to 48 bits.
Because of truncation, last bit is not as good as round-to-nearest, with slight bias.
Let's say it got effectively 47 bits precision, or about 47/3.322 ~ 14 decimals

PPL is much slower, probably doing BCD math (15 internally, rounded to 12 decimals)

BTW, Python user is more comfortable counting from zero.
For 2499 loops, range(2499) look better than range(1,2500)
Doing Savage simulation, using Python gmpy2 / pdeclib (n=2499, radian mode):

12-decimals (halfway to even) => a = 2499.99942 402, relative error ~ 2.3E-7
48-bits CAS float (simulated) ==> a = 2499.99998 195, relative error ~ 7.2E-9

RoundToNearest:
48-bits => a = 2500.00000 041, relative error ~ 1.7E-10
47-bits => a = 2499.99999 957, relative error ~ 1.7E-10
46-bits => a = 2499.99999 984, relative error ~ 6.6E-11
45-bits => a = 2500.00000 108, relative error ~ 4.3E-10
44-bits => a = 2500.00000 179, relative error ~ 7.2E-10
43-bits => a = 2500.00000 463, relative error ~ 1.9E-9
42-bits => a = 2500.00001 457, relative error ~ 5.8E-9 <== CAS float ~ 42 bits
...
37-bits => a = 2500.00032 413, relative error ~ 1.3E-7 <== 12-decimals ~ 37 bits

CAS float is worse than expected due to its biased toward zero rounding.
12-decimals do not get back 40 bits. Decimals roundings had bigger "gap", not 1 ULP ...

Does above numbers match your Android emulation ?
I get:
2499.99948647, relative error 0.000000205412, for PPL, and
2499.99998195, relative error 0.00000000722, for Python-in-CAS.
And of course 2500, 0, for the exact CAS.
I have noticed an interesting feature of my Pythons-in-CAS timings on the Android.

Sometimes, I see timings of about 100 ms (i.e. faster than PPL). Sometimes, I see timings of about 2.7s (i.e. comparable to exact-CAS timings). But these are not random - once I see one value, it tends to repeat (with small variations).

In contrast, the other timings show little variation.
Version 0.5 is not intended to change timings, but the timings for pythons-in-CAS do seem to be getting slower.

I seemed to have to run Savage V0.4 again before seeing the shorter times in V0.5 - which has me wondering which result is the more representative.
Is anyone else seeing a problem?

Outside the timed code, PRINT can be suppressed using boolean SP, and TEVAL timings are now returned by the main program.
GETNTIMES allows a timing to be repeated, to check repeatability.

Code:

//Benchmark: Savage 
 LOCAL CRID:="Savage Benchmark (HP Prime) V0.5"; 
 EXPORT NAMES:={
  "PPL       ",
  "MAKELIST  ",
  "PythonsCAS",
  "CAS       ",
  "CASinPPL  "};

 //OMITTED: "RAD" in the original:
 //User must select Radians

 EXPORT SP:=1;//ShowPRINT

 LOCAL AA;

 EXPORT SavagePPL()
 BEGIN
  LOCAL AA;
  AA:=1;
  FOR I FROM 1 TO 2499 DO
    AA:=TAN(ATAN(EXP(LN(√(AA*AA)))))+1
  END;
  RETURN AA;
 END;

 MLFOR ()
 BEGIN
  //LOCAL AA;
  RETURN AA:=TAN(ATAN(EXP(LN(√(AA*AA)))))+1;
 END;
 
 EXPORT SavageMAKE()
 BEGIN
  //LOCAL AA;
  AA:=1;
  MAKELIST(MLFOR(),AA,1,2499);
  RETURN AA;
 END;

#CAS
 SavageCAS1(f):=
 BEGIN
  LOCAL aa;
  aa:=1;
  FOR I FROM 1 TO 2499 DO
    aa:=TAN(ATAN(EXP(LN(√(aa*aa)))))+1
  END;
  RETURN (aa);
 END;

def savagepythonssyn() :
   local ii,aa
   aa=1
   for ii in range(1,2500):
     aa= tan(atan(exp(log(sqrt(aa*aa)))))+1
#END

 EXPORT SavageCASinPPL()
 BEGIN
  LOCAL aa;
  aa:=1;
  FOR I FROM 1 TO 2499 DO
    aa:=CAS(TAN(ATAN(EXP(LN(√(aa*aa))))))+1;
  END;
  RETURN (aa);
 END;

 RRR(RR)
 //REPORT RESULT,RELATIVE ERROR
 BEGIN
  RETURN {RR,((2500-RR)/2500)};
 END;

 //APPROX:
 //I FIND NO CLEAR WINNER BETWEEN PPL AND MAKE.
 //EXACT:
 //I FIND CAS2 CONSISTENTLY FASTER THAN CAS1
 
 SPRINT(ONE)
 BEGIN
  IF SP THEN
   PRINT(ONE);
  END;
 END;

 EXPORT GETNTIMES(FunN,NN)
 BEGIN
  LOCAL II;
  LOCAL TM:={};
  FOR II FROM 1 TO NN DO
   CASE
   IF  FunN==1 THEN TM(0):=TEVAL(SavagePPL);  END;
   IF  FunN==2 THEN TM(0):=TEVAL(SavageMAKE);  END;
   IF  FunN==3 THEN TM(0):=TEVAL(savagepysyn());  END;
   IF  FunN==4 THEN TM(0):=TEVAL(SavageCAS1);  END;
   IF  FunN==5 THEN TM(0):=TEVAL(SavageCASinPPL);  END;
   DEFAULT
   END;
  END;
  RETURN TM;
 END;

 EXPORT SAVAGE()
 BEGIN
  //LOCAL aa;
  LOCAL RR;
  LOCAL TM:={};
  IF SP THEN
   PRINT();
  END;
  SPRINT(CRID);
  TM(0):=TEVAL(RR:=SavagePPL());
  SPRINT({NAMES(1),TM(0),RRR(RR)});
  TM(0):=TEVAL(RR:=SavageMAKE());
  SPRINT({NAMES(2),TM(0),RRR(RR)});
  TM(0):=TEVAL(savagepysyn());
  //PRINT(TM(O));//DEBUG
  SPRINT({NAMES(3),TM(0),RRR(aa)});
  TM(0):=TEVAL(RR:=SavageCAS1(""));
  SPRINT({NAMES(4),TM(0),RRR(RR)});
  TM(0):=TEVAL(RR:=SavageCASinPPL());
  SPRINT({NAMES(5),TM(0),RRR(RR)});
 
  SPRINT(CRID);
  //MSGBOX(TM);
  RETURN TM;
 END;
Note: Neither V0.4 nor V0.5 compile in Beta on Android...
Version 0.2 can be compiled in Beta if "I" is changed to "i".
Update: See note regarding Python-in-CAS affecting indexing.
Note: Versions 0.3Beta, 0.4 and 0.5 utilise Python-in-CAS code.
This thread http://www.hpmuseum.org/forum/thread-116...#pid106892
Points out that such Python-in-CAS code can affect indexing system-wide.
As such, these versions are not recommended.
Reference URL's