Expose bcmath to javascript

I work on a productivity suite that requires precision calculations. 99% of the time we do these server side using the bcmath library, because for the handling of money in the millions of dollars using floating point math sucks big time.

Clients want some real time functionality so this afternoon I broke down and wrote a brief library with the Prototype framework to expose the PHP bcmath lib to synchronous calls from the client.

In addition to all the standard bcmath functions I include two extra functions - BC.product and BC.sum. These functions take an array of numbers and aggregate them (to avoid the overhead of repeated SJAX calls).

Note that the JS here is written to put the browser in synchronous mode unlike the usual asynchronous requirements. Since the PHP side doesn’t try to start a database or any other overhead actions it should be lightning fast. It has to be since a synchronous request locks the browser up until it finishes - so if you use this code avoid spamming the calls (that’s why BC.product and BC.sum are added).

It would be preferable to have a js bcmath equivalent in the client side, but that’s beyond my skill.

I’ve been testing the code in the Firebug console, and it seems to be working.

This is very small so I’ll share it with everyone here. I could use help in verifying it works across all browsers. MIT license…

js side…


BC: {
	scale: 2,
		
	_request: function ( f, p ) {
		return new Ajax.Request( 'bcmath.php', {
			method: 'post',
			parameters: {
				'call': f,
				'params[]': p,
				'scale' : this.scale
			},
			asynchronous: false
		}).transport.responseText;
	},
		
	add: function ( l, r ) { return this._request( 'add', [ l, r ]); },	
	comp: function ( l, r ) { return this._request( 'comp', [ l, r ]); },
	div: function ( l, r ) { return this._request( 'div', [ l, r ]); },
	mod: function ( l, m ) { return this._request( 'mod', [ l, m ]); },
	mul: function ( l, r ) { return this._request( 'mul', [ l, r ]); },
	pow: function ( l, r ) { return this._request( 'pow', [ l, r ]); },
	powmod: function ( l, r, m ) { return this._request( 'powmod', [ l, r, m ]); },
	product: function ( a ) { return this._request( 'product', a ); },	
	sqrt: function ( o ) { return this._request('sqrt', p); },
	sub: function ( l, r ) { return this._request( 'sub', [ l, r ] ); },	
	sum: function ( a ) { return this._request('sum', a ); }
}

The “bcmath.php” file that js above must call.



<?php
/**
 * This code is called SYNCRHONOUSLY! This means this must act as FAST AS POSSIBLE.
 */

header("HTTP/1.0 200");
header("Content-Type: text/plain");
header("Pragma: No-cache");

switch ($_POST['call']) {
	case 'add': echo bcadd($_POST['params'][0], $_POST['params'][1], $_POST['scale']); break;
	case 'comp': echo bccomp($_POST['params'][0], $_POST['params'][1], $_POST['scale']); break;	
	case 'div': echo bcdiv($_POST['params'][0], $_POST['params'][1], $_POST['scale']); break;	
	case 'mod': echo bcmod($_POST['params'][0], $_POST['params'][1]); break;	
	case 'mul': echo bcmul($_POST['params'][0], $_POST['params'][1], $_POST['scale']); break;	
	case 'pow': echo bcpow($_POST['params'][0], $_POST['params'][1], $_POST['scale']); break;	
	case 'powmod': echo bcmul($_POST['params'][0], $_POST['params'][1], $_POST['params'][2], $_POST['scale']); break;	
	case 'sqrt': echo bcsqrt($_POST['params'][0], $_POST['scale']); break;	
	case 'sub': echo bcsub($_POST['params'][0], $_POST['params'][1], $_POST['scale']); break;
	case 'product':
		$total = '0';
		foreach ($_POST['params'] as $p) {
			$total = bcmul( $total, $p, $_POST['scale']);
		}
		echo $total;
	break;
	case 'sum':
		$total = '0';
		foreach ($_POST['params'] as $p) {
			$total = bcadd( $total, $p, $_POST['scale']);
		}
		echo $total;
	break;
	default:
		header("HTTP/1.0 400");
		echo 'Bad Request.';
	break;
}

exit;

I probably should use $_GET instead of $_POST in the final version.

Instead of expending bandwidth (and latency) for every single calculation you perform, the best suggestion I’ve heard of when dealing with currency is to perform your currency work in terms of cents. That way you’re mostly dealing with integers, which have less problems when it comes to calculations.

However, if you do require to use bcmath from javascript, there is something that fulfills that requirement: BCMath Library for JavaScript

I’ve tried that out actually. That project has not been updated in 3 years and is EXTREMELY buggy and inaccurate on routine calculations. Until it is fully debugged it’s useless. It was a nice try.

For my current project the latency isn’t an issue - each server is onsite with up to 8 client computers so I can live with this solution. It would be better to do it on the client, but that bug ridden mess you cited isn’t going to work.

About the only other native javascript library worth a try is the BigInteger one.

Failing that, you may already have the best solution that’s available.

My coworker dug that one up last night. It does look promising.

In any event the code above is illustrative of the more rarely used Synchronous mode of the XMLHTTPRequest module. If nothing else it’s instructive which is the main reason I posted it.