2008-08-09 18:33:35 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
2008-08-08 18:15:46 -06:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2008-11-17 14:58:45 -07:00
|
|
|
#include <u.h>
|
|
|
|
#include <errno.h>
|
2008-08-08 18:15:46 -06:00
|
|
|
#include "go.h"
|
|
|
|
|
2008-10-29 13:46:44 -06:00
|
|
|
/// uses arithmetic
|
2008-08-09 18:33:35 -06:00
|
|
|
|
2008-08-12 15:04:03 -06:00
|
|
|
int
|
|
|
|
mpcmpfixflt(Mpint *a, Mpflt *b)
|
|
|
|
{
|
|
|
|
char buf[500];
|
|
|
|
Mpflt c;
|
|
|
|
|
|
|
|
sprint(buf, "%B", a);
|
|
|
|
mpatoflt(&c, buf);
|
|
|
|
return mpcmpfltflt(&c, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
mpcmpfltfix(Mpflt *a, Mpint *b)
|
|
|
|
{
|
|
|
|
char buf[500];
|
|
|
|
Mpflt c;
|
|
|
|
|
|
|
|
sprint(buf, "%B", b);
|
|
|
|
mpatoflt(&c, buf);
|
|
|
|
return mpcmpfltflt(a, &c);
|
|
|
|
}
|
|
|
|
|
2008-08-08 18:15:46 -06:00
|
|
|
int
|
|
|
|
mpcmpfixfix(Mpint *a, Mpint *b)
|
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
Mpint c;
|
|
|
|
|
|
|
|
mpmovefixfix(&c, a);
|
|
|
|
mpsubfixfix(&c, b);
|
|
|
|
return mptestfix(&c);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
mpcmpfixc(Mpint *b, vlong c)
|
|
|
|
{
|
|
|
|
Mpint a;
|
|
|
|
|
|
|
|
mpmovecfix(&a, c);
|
|
|
|
return mpcmpfixfix(&a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
mpcmpfltflt(Mpflt *a, Mpflt *b)
|
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
Mpflt c;
|
|
|
|
|
|
|
|
mpmovefltflt(&c, a);
|
|
|
|
mpsubfltflt(&c, b);
|
|
|
|
return mptestflt(&c);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2008-08-09 18:33:35 -06:00
|
|
|
mpcmpfltc(Mpflt *b, double c)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
Mpflt a;
|
2008-08-08 18:15:46 -06:00
|
|
|
|
|
|
|
mpmovecflt(&a, c);
|
|
|
|
return mpcmpfltflt(&a, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mpsubfixfix(Mpint *a, Mpint *b)
|
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
mpnegfix(b);
|
|
|
|
mpaddfixfix(a, b);
|
|
|
|
mpnegfix(b);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-08-09 18:33:35 -06:00
|
|
|
mpsubfltflt(Mpflt *a, Mpflt *b)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
mpnegflt(b);
|
|
|
|
mpaddfltflt(a, b);
|
|
|
|
mpnegflt(b);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-08-09 18:33:35 -06:00
|
|
|
mpaddcfix(Mpint *a, vlong c)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
Mpint b;
|
2008-08-08 18:15:46 -06:00
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecfix(&b, c);
|
|
|
|
mpaddfixfix(a, &b);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-08-09 18:33:35 -06:00
|
|
|
mpaddcflt(Mpflt *a, double c)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
Mpflt b;
|
2008-08-08 18:15:46 -06:00
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecflt(&b, c);
|
|
|
|
mpaddfltflt(a, &b);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmulcfix(Mpint *a, vlong c)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
Mpint b;
|
2008-08-08 18:15:46 -06:00
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecfix(&b, c);
|
|
|
|
mpmulfixfix(a, &b);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmulcflt(Mpflt *a, double c)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
Mpflt b;
|
2008-08-08 18:15:46 -06:00
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecflt(&b, c);
|
|
|
|
mpmulfltflt(a, &b);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-08-09 18:33:35 -06:00
|
|
|
mpdivfixfix(Mpint *a, Mpint *b)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
Mpint q, r;
|
2008-08-08 18:15:46 -06:00
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
mpdivmodfixfix(&q, &r, a, b);
|
|
|
|
mpmovefixfix(a, &q);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmodfixfix(Mpint *a, Mpint *b)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
Mpint q, r;
|
2008-08-08 18:15:46 -06:00
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
mpdivmodfixfix(&q, &r, a, b);
|
|
|
|
mpmovefixfix(a, &r);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-08-09 18:33:35 -06:00
|
|
|
mpcomfix(Mpint *a)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
Mpint b;
|
2008-08-08 18:15:46 -06:00
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecfix(&b, 1);
|
|
|
|
mpnegfix(a);
|
|
|
|
mpsubfixfix(a, &b);
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mpmovefixflt(Mpflt *a, Mpint *b)
|
|
|
|
{
|
2008-11-17 14:58:45 -07:00
|
|
|
mpmovecflt(a, mpgetfixflt(b));
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mpmovefltfix(Mpint *a, Mpflt *b)
|
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecfix(a, mpgetflt(b));
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovefixfix(Mpint *a, Mpint *b)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
*a = *b;
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovefltflt(Mpflt *a, Mpflt *b)
|
2008-08-08 18:15:46 -06:00
|
|
|
{
|
2008-08-09 18:33:35 -06:00
|
|
|
*a = *b;
|
2008-08-08 18:15:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// power of ten
|
|
|
|
//
|
|
|
|
static double
|
|
|
|
tentab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 };
|
|
|
|
|
|
|
|
static double
|
|
|
|
dppow10(int n)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if(n < 0)
|
|
|
|
return 1.0/dppow10(-n);
|
|
|
|
|
|
|
|
if(n < nelem(tentab))
|
|
|
|
return tentab[n];
|
|
|
|
|
|
|
|
i = n/2;
|
|
|
|
return dppow10(i) * dppow10(n-i);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// floating point input
|
|
|
|
// required syntax is [+-]d*[.]d*[e[+-]d*]
|
|
|
|
//
|
|
|
|
void
|
|
|
|
mpatoflt(Mpflt *a, char *as)
|
|
|
|
{
|
|
|
|
int dp, c, f, ef, ex, zer;
|
|
|
|
char *s;
|
2008-11-17 14:58:45 -07:00
|
|
|
double f64;
|
|
|
|
|
|
|
|
/* until Mpflt is really mp, use strtod to get rounding right */
|
|
|
|
errno = 0;
|
|
|
|
f64 = strtod(as, &s);
|
|
|
|
mpmovecflt(a, f64);
|
|
|
|
if(errno != 0)
|
|
|
|
a->ovf = 1;
|
|
|
|
return;
|
2008-08-08 18:15:46 -06:00
|
|
|
|
|
|
|
s = as;
|
|
|
|
dp = 0; /* digits after decimal point */
|
|
|
|
f = 0; /* sign */
|
|
|
|
ex = 0; /* exponent */
|
|
|
|
zer = 1; /* zero */
|
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecflt(a, 0.0);
|
2008-08-08 18:15:46 -06:00
|
|
|
for(;;) {
|
|
|
|
switch(c = *s++) {
|
|
|
|
default:
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
case '-':
|
|
|
|
f = 1;
|
|
|
|
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
|
|
|
case '+':
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case '.':
|
|
|
|
dp = 1;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
|
|
|
case '8':
|
|
|
|
case '9':
|
|
|
|
zer = 0;
|
|
|
|
|
|
|
|
case '0':
|
|
|
|
mpmulcflt(a, 10);
|
|
|
|
mpaddcflt(a, c-'0');
|
|
|
|
if(dp)
|
|
|
|
dp++;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case 'E':
|
|
|
|
case 'e':
|
|
|
|
ex = 0;
|
|
|
|
ef = 0;
|
|
|
|
for(;;) {
|
|
|
|
c = *s++;
|
|
|
|
if(c == '+' || c == ' ' || c == '\t')
|
|
|
|
continue;
|
|
|
|
if(c == '-') {
|
|
|
|
ef = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(c >= '0' && c <= '9') {
|
|
|
|
ex = ex*10 + (c-'0');
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(ef)
|
|
|
|
ex = -ex;
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(dp)
|
|
|
|
dp--;
|
|
|
|
if(mpcmpfltc(a, 0.0) != 0)
|
|
|
|
mpmulcflt(a, dppow10(ex-dp));
|
|
|
|
if(f)
|
|
|
|
mpnegflt(a);
|
|
|
|
return;
|
|
|
|
|
|
|
|
bad:
|
2008-11-17 14:58:45 -07:00
|
|
|
warn("set ovf in mpatof: %s", as);
|
2008-08-08 18:15:46 -06:00
|
|
|
mpmovecflt(a, 0.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// fixed point input
|
|
|
|
// required syntax is [+-][0[x]]d*
|
2008-11-17 14:58:45 -07:00
|
|
|
//
|
2008-08-08 18:15:46 -06:00
|
|
|
void
|
|
|
|
mpatofix(Mpint *a, char *as)
|
|
|
|
{
|
|
|
|
int c, f;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
s = as;
|
|
|
|
f = 0;
|
|
|
|
mpmovecfix(a, 0);
|
|
|
|
|
|
|
|
c = *s++;
|
|
|
|
switch(c) {
|
|
|
|
case '-':
|
|
|
|
f = 1;
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
c = *s++;
|
|
|
|
if(c != '0')
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '0':
|
|
|
|
goto oct;
|
|
|
|
}
|
|
|
|
|
|
|
|
while(c) {
|
|
|
|
if(c >= '0' && c <= '9') {
|
|
|
|
mpmulcfix(a, 10);
|
|
|
|
mpaddcfix(a, c-'0');
|
|
|
|
c = *s++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
oct:
|
|
|
|
c = *s++;
|
|
|
|
if(c == 'x' || c == 'X')
|
|
|
|
goto hex;
|
|
|
|
while(c) {
|
|
|
|
if(c >= '0' && c <= '7') {
|
|
|
|
mpmulcfix(a, 8);
|
|
|
|
mpaddcfix(a, c-'0');
|
|
|
|
c = *s++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
hex:
|
|
|
|
c = *s++;
|
|
|
|
while(c) {
|
|
|
|
if(c >= '0' && c <= '9') {
|
|
|
|
mpmulcfix(a, 16);
|
|
|
|
mpaddcfix(a, c-'0');
|
|
|
|
c = *s++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(c >= 'a' && c <= 'f') {
|
|
|
|
mpmulcfix(a, 16);
|
|
|
|
mpaddcfix(a, c+10-'a');
|
|
|
|
c = *s++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(c >= 'A' && c <= 'F') {
|
|
|
|
mpmulcfix(a, 16);
|
|
|
|
mpaddcfix(a, c+10-'A');
|
|
|
|
c = *s++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if(f)
|
|
|
|
mpnegfix(a);
|
|
|
|
return;
|
|
|
|
|
|
|
|
bad:
|
|
|
|
warn("set ovf in mpatov: %s", as);
|
|
|
|
mpmovecfix(a, 0);
|
|
|
|
}
|
2008-08-11 14:22:04 -06:00
|
|
|
|
|
|
|
int
|
|
|
|
Bconv(Fmt *fp)
|
|
|
|
{
|
|
|
|
char buf[500], *p;
|
|
|
|
Mpint *xval, q, r, ten;
|
|
|
|
int f;
|
|
|
|
|
|
|
|
xval = va_arg(fp->args, Mpint*);
|
|
|
|
mpmovefixfix(&q, xval);
|
|
|
|
f = 0;
|
|
|
|
if(mptestfix(&q) < 0) {
|
|
|
|
f = 1;
|
|
|
|
mpnegfix(&q);
|
|
|
|
}
|
|
|
|
mpmovecfix(&ten, 10);
|
|
|
|
|
|
|
|
p = &buf[sizeof(buf)];
|
|
|
|
*--p = 0;
|
|
|
|
for(;;) {
|
|
|
|
mpdivmodfixfix(&q, &r, &q, &ten);
|
|
|
|
*--p = mpgetfix(&r) + '0';
|
|
|
|
if(mptestfix(&q) <= 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(f)
|
|
|
|
*--p = '-';
|
|
|
|
return fmtstrcpy(fp, p);
|
|
|
|
}
|