Posted to tcl by sebres at Thu Aug 29 14:15:30 GMT 2019view pretty
/*
* tclfastinvsqrt.c --
*
* Test module to get native handle of channel.
*
* Compile:
* mingw: gcc -O2 -DUSE_TCL_STUBS=1 -I$tcl/win -I$tcl/generic tclfastinvsqrt.c -shared -o tclfastinvsqrt.dll libtclstub86.a
* *nix: gcc -O2 -DUSE_TCL_STUBS=1 -I$tcl/unix -I$tcl/generic tclfastinvsqrt.c -shared -o tclfastinvsqrt.so libtclstub86.a
*
* Usage:
* $ tclsh86
* % load tclfastinvsqrt
* % expr {invsqrt(10)}
*/
#include "tcl.h"
static inline double
FastInvSqrt(double x, int accuracy) {
char *buf = (char *)&x;
double xhalf = 0.5f * x;
Tcl_WideInt i = *(Tcl_WideInt*)buf;
i = 0x5fe6eb50c7b537a9 - (i >> 1);
buf = (char *)&i;
x = *(double*)buf;
while (accuracy--) {
x = x*(1.5-(xhalf*x*x));
}
return x;
}
int
FastInvSqrtCmd(
ClientData dummy,
Tcl_Interp* interp,
int objc,
Tcl_Obj * const objv[]
) {
double dbl;
int accuracy = 4;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "value ?accuracy?");
return TCL_ERROR;
}
if (Tcl_GetDoubleFromObj(interp, objv[1], &dbl) != TCL_OK) {
return TCL_ERROR;
}
if (objc > 2 && Tcl_GetIntFromObj(interp, objv[2], &accuracy) != TCL_OK) {
return TCL_ERROR;
}
dbl = FastInvSqrt(dbl, accuracy);
Tcl_SetObjResult(interp, Tcl_NewDoubleObj(dbl));
return TCL_OK;
}
int
Tclfastinvsqrt_Init(Tcl_Interp *interp) {
if (!Tcl_InitStubs(interp, "8.5", 0)) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "::tcl::mathfunc::invsqrt", FastInvSqrtCmd, NULL, NULL);
return TCL_OK;
}
/*
load tclfastinvsqrt
# speed vs accuracy:
set tm 500
for {set x 2} {$x < 100000} {set x [expr {$x * 10}]} {
puts $x:\t[timerate { expr { 1 / sqrt($x) } } $tm]
puts \t[timerate { expr { invsqrt($x,1) } } $tm]
puts \t[timerate { expr { invsqrt($x) } } $tm]
}
# accuracy :
for {set x 2} {$x < 100000} {set x [expr {$x * 10}]} {
puts $x:\t[expr { 1 / sqrt($x) }]
puts \t[expr { invsqrt($x) }]
}
for {set x 2} {$x < 100000} {set x [expr {$x * 10}]} {
puts $x:\t[expr { 1 / sqrt($x) }]
puts \t[expr { invsqrt($x,1) }]
}
# Herbie example:
for {set x 2} {$x < 100000} {set x [expr {$x * 10}]} {
puts $x:\t[expr { sqrt($x+1) - sqrt($x) }]
puts \t[expr { 1 / (sqrt($x+1) + sqrt($x)) }]
puts \t[expr { invsqrt( (2*$x + 1 + 2/invsqrt(($x+1)*$x)) ) }]
}
*/
Comments
Posted by sebres at Thu Aug 29 15:02:08 GMT 2019 [text] [code]
the comments about channel was copy&paste, simply ignore it :)