mailing list of musl libc
 help / color / mirror / code / Atom feed
* ccalc.c for testing math functions
@ 2013-06-24 19:08 Rich Felker
  0 siblings, 0 replies; only message in thread
From: Rich Felker @ 2013-06-24 19:08 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 530 bytes --]

Here is a quick test program I wrote for playing around with musl's
(or any libc/libm's) math functions. It's an RPN calculator that
accepts input in argv[1] or stdin. It's by no means mature, but it's
very simple and usable for the purpose for which it was written
(testing), and the concepts in it could easily be extended to build a
nice infix-notation direct-libm-based floating point expression
evaluator library or utility.

Example usage:

$ ./ccalc '-1 csqrt 1 atan 2 * 3 / * cexp p'
0.866025403784438596588 + i*0.5

Rich

[-- Attachment #2: ccalc.c --]
[-- Type: text/plain, Size: 5058 bytes --]

/*
 * ccalc.c - C calculator (RPN)
 * by Rich Felker, placed in the public domain
 *
 * This program implements a simplistic RPN calculator that directly
 * uses the system's C floating point operators (on complex long
 * double) and functions (on their respective argument types) for the
 * purpose of comparing and testing implementation behavior. In
 * addition the the standard functions, the following commands are
 * available:
 *
 * p - print the top of the stack to DECIMAL_DIG significant figures
 * x - print the current floating point exception flags' status
 *
 * No error checking for stack overflow or underflow is performed in
 * this version, so it is not safe for use with untrusted input.
 */

#include <math.h>
#include <complex.h>
#include <float.h>
#include <fenv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define COMPLEX 1
#define LDBL 2
#define FLOAT 4

#define FUNCR(x) \
{ #x, (void (*)())x, 0 }, \
{ #x "f", (void (*)())x##f, FLOAT }, \
{ #x "l", (void (*)())x##l, LDBL }

#define FUNCC(x) \
{ #x, (void (*)())x, COMPLEX }, \
{ #x "f", (void (*)())x##f, COMPLEX|FLOAT }, \
{ #x "l", (void (*)())x##l, COMPLEX|LDBL }

#define FUNC(x) FUNCR(x), FUNCC(c##x)

struct func {
	char name[16];
	void (*addr)();
	unsigned flags;
};

/* missing: fma, frexp, ilogb, ldexp, llrint, llround, lrint, lround,
 * nexttoward, remquo, scalbln, scalbn */

static const struct func unary_funcs[] = {
	FUNC(acos), FUNC(acosh), FUNC(asin), FUNC(asinh),
	FUNC(atan), FUNC(atanh), FUNC(cos), FUNC(cosh),
	FUNC(sin), FUNC(sinh), FUNC(tan), FUNC(tanh),
	FUNC(exp), FUNC(log), FUNC(sqrt),

	FUNCR(cbrt), FUNCR(fabs),
	FUNCR(exp2), FUNCR(expm1),
	FUNCR(erf), FUNCR(erfc),
	FUNCR(log10), FUNCR(log1p), FUNCR(log2), FUNCR(logb),
	FUNCR(ceil), FUNCR(floor), FUNCR(nearbyint),
	FUNCR(rint), FUNCR(round), FUNCR(trunc),
	FUNCR(lgamma), FUNCR(tgamma),

	FUNCC(carg), FUNCC(cimag), FUNCC(creal), FUNCC(cproj), FUNCC(conj),
 
	{0}
};

static const struct func binary_funcs[] = {
	FUNCR(atan2), FUNCR(copysign), FUNCR(fdim),
	FUNCR(fmax), FUNCR(fmin), FUNCR(fmod), FUNCR(hypot),
	FUNC(pow), FUNCR(remainder), FUNCR(nextafter),
	{0}
};

int main(int argc, char **argv)
{
	char token[20000], *end;
	complex long double stack[100];
	int sp = 0;
	const struct func *f;
	FILE *in = stdin;
	int except;

	if (argc>1) in = fmemopen(argv[1], strlen(argv[1]), "r");
	setvbuf(in, 0, _IONBF, 0);

	while (fscanf(in, "%19999s", token)==1) {
		end = 0;
		stack[sp] = strtod(token, &end);
		if (end != token) switch (*end) {
		case 'f': case 'F':
			stack[sp++] = strtof(token, 0);
			continue;
		case 'l': case 'L':
			stack[sp++] = strtold(token, 0);
			continue;
		case 0:
			sp++;
			continue;
		}
		sp--;
		if (!token[1]) switch (token[0]) {
		case '+':
			stack[sp-1] += stack[sp];
			continue;
		case '-':
			stack[sp-1] -= stack[sp];
			continue;
		case '*':
			stack[sp-1] *= stack[sp];
			continue;
		case '/':
			stack[sp-1] /= stack[sp];
			continue;
		case 'p':
			printf("%.*Lg + i*%.*Lg\n",
				DECIMAL_DIG, creall(stack[sp]),
				DECIMAL_DIG, cimagl(stack[sp]));
			sp++;
			continue;
		case 'x':
			except = fetestexcept(FE_ALL_EXCEPT);
			if (!except) printf("NONE");
			if (except & FE_INVALID) printf("INVALID ");
			if (except & FE_OVERFLOW) printf("OVERFLOW ");
			if (except & FE_UNDERFLOW) printf("UNDERFLOW ");
			if (except & FE_INEXACT) printf("INEXACT ");
			putchar('\n');
			sp++;
			continue;
		}
		sp++;
		f = unary_funcs;
		for (; f->addr; f++) {
			if (strcmp(f->name, token)) continue;
			switch(f->flags) {
			case 0:
				stack[sp-1] = ((double (*)(double))f->addr)(stack[sp-1]);
				break;
			case FLOAT:
				stack[sp-1] = ((float (*)(float))f->addr)(stack[sp-1]);
				break;
			case LDBL:
				stack[sp-1] = ((long double (*)(long double))f->addr)(stack[sp-1]);
				break;
			case COMPLEX:
				stack[sp-1] = ((complex double (*)(complex double))f->addr)(stack[sp-1]);
				break;
			case COMPLEX|FLOAT:
				stack[sp-1] = ((complex float (*)(complex float))f->addr)(stack[sp-1]);
				break;
			case COMPLEX|LDBL:
				stack[sp-1] = ((complex long double (*)(complex long double))f->addr)(stack[sp-1]);
				break;
			}
			break;
		}
		f = binary_funcs;
		for (; f->addr; f++) {
			if (strcmp(f->name, token)) continue;
			sp--;
			switch(f->flags) {
			case 0:
				stack[sp-1] = ((double (*)(double,double))f->addr)(stack[sp-1], stack[sp]);
				break;
			case FLOAT:
				stack[sp-1] = ((float (*)(float,float))f->addr)(stack[sp-1], stack[sp]);
				break;
			case LDBL:
				stack[sp-1] = ((long double (*)(long double,long double))f->addr)(stack[sp-1], stack[sp]);
				break;
			case COMPLEX:
				stack[sp-1] = ((complex double (*)(complex double,complex double))f->addr)(stack[sp-1], stack[sp]);
				break;
			case COMPLEX|FLOAT:
				stack[sp-1] = ((complex float (*)(complex float,complex float))f->addr)(stack[sp-1], stack[sp]);
				break;
			case COMPLEX|LDBL:
				stack[sp-1] = ((complex long double (*)(complex long double,complex long double))f->addr)(stack[sp-1], stack[sp]);
				break;
			}
			break;
		}
	}
	return 0;
}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2013-06-24 19:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-24 19:08 ccalc.c for testing math functions Rich Felker

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).