Skip to content

Commit d939cb5

Browse files
Tom St Denissjaeckel
Tom St Denis
authored andcommitted
added libtomfloat-0.02
1 parent 6c3b48a commit d939cb5

17 files changed

+299
-35
lines changed

changes.txt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1-
May 5th, 2004 v0.01 -- wrote base of LTF
1+
June 21st, 2004
2+
v0.02 -- Added missing objects to the makefile [oops]
3+
-- fixed up mpf_add and mpf_sub to be more reliable about the precision
4+
-- added required limited ln function mpf_ln_l (domain 0 < x <= 2)
5+
It's still incomplete as it converges slowly (and therefore yields incorrect results)
6+
-- Added mpf_ln and mpf_atan
7+
-- Added short-circuits to sin, cos, invsqrt, atan, ln and sqrt [huge speedup]
8+
-- Optimized mpf_sqrt and mpf_invsqrt by using quick estimates. Fixed
9+
circular dependency as well (mpf_sqrt requires mpf_invsqrt but not vice versa)
10+
++ Note: No further releases are planned for a while. I encourage interested
11+
parties to fork this code base and extend it!
12+
13+
May 5th, 2004
14+
v0.01 -- wrote base of LTF
215

3-
Anytime v0.00 -- no LTF existed.
16+
Anytime
17+
v0.00 -- no LTF existed.

demos/ex1.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ void draw(mp_float *a)
1010
int main(void)
1111
{
1212
mp_float a, b, c, d, e;
13-
mpf_init_multi(96, &a, &b, &c, &d, &e, NULL);
13+
int err;
14+
15+
mpf_init_multi(100, &a, &b, &c, &d, &e, NULL);
1416

1517
mpf_const_d(&a, 1); draw(&a);
1618
mpf_const_d(&b, 2); draw(&b);
@@ -21,6 +23,12 @@ int main(void)
2123
mpf_sub(&b, &c, &e); printf("2 - 3 =="); draw(&e);
2224
mpf_mul(&b, &c, &e); printf("2 * 3 == "); draw(&e);
2325
mpf_div(&b, &c, &e); printf("2 / 3 == "); draw(&e);
26+
mpf_add_d(&b, 3, &e); printf("2 + 3 == "); draw(&e);
27+
mpf_sub_d(&b, 3, &e); printf("2 - 3 =="); draw(&e);
28+
mpf_mul_d(&b, 3, &e); printf("2 * 3 == "); draw(&e);
29+
mpf_div_d (&b, 3, &e); printf("2 / 3 == "); draw(&e);
30+
mpf_const_d(&e, 0); mpf_add_d(&e, 1, &e); printf("0 + 1 == "); draw(&e);
31+
mpf_const_d(&e, 0); mpf_sub_d(&e, 1, &e); printf("0 - 1 == "); draw(&e);
2432
printf("\n");
2533
mpf_invsqrt(&d, &e); printf("1/sqrt(4) == 1/2 == "); draw(&e);
2634
mpf_invsqrt(&c, &e); printf("1/sqrt(3) == "); draw(&e);
@@ -29,6 +37,8 @@ int main(void)
2937
mpf_inv(&c, &e); printf("1/3 == "); draw(&e);
3038
mpf_inv(&d, &e); printf("1/4 == "); draw(&e);
3139
printf("\n");
40+
mpf_const_pi(&e); printf("Pi == "); draw(&e);
41+
printf("\n");
3242
mpf_const_e(&e); printf("e == "); draw(&e);
3343
mpf_exp(&c, &e); printf("e^3 == "); draw(&e);
3444
mpf_sqrt(&e, &e); printf("sqrt(e^3) == "); draw(&e);
@@ -46,7 +56,21 @@ int main(void)
4656
mpf_tan(&b, &e); printf("tan(2) == "); draw(&e);
4757
mpf_tan(&c, &e); printf("tan(3) == "); draw(&e);
4858
mpf_tan(&d, &e); printf("tan(4) == "); draw(&e);
59+
mpf_inv(&a, &e); mpf_atan(&e, &e); printf("atan(1/1) == "); draw(&e);
60+
mpf_inv(&b, &e); mpf_atan(&e, &e); printf("atan(1/2) == "); draw(&e);
61+
mpf_inv(&c, &e); mpf_atan(&e, &e); printf("atan(1/3) == "); draw(&e);
62+
mpf_inv(&d, &e); mpf_atan(&e, &e); printf("atan(1/4) == "); draw(&e);
4963
printf("\n");
64+
#define lntest(x) if ((err = mpf_const_ln_d(&e, x)) != MP_OKAY) { printf("Failed ln(%3d), %d\n", x, err); } else { printf("ln(%3d) == ", x); draw(&e); };
65+
lntest(0);
66+
lntest(1);
67+
lntest(2);
68+
lntest(4);
69+
lntest(8);
70+
lntest(17);
71+
lntest(1000);
72+
lntest(100000);
73+
lntest(250000);
5074
return 0;
5175
}
5276

float.pdf

-360 Bytes
Binary file not shown.

float.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
\begin{document}
5050
\frontmatter
5151
\pagestyle{empty}
52-
\title{LibTomFloat User Manual \\ v0.01}
52+
\title{LibTomFloat User Manual \\ v0.02}
5353
\author{Tom St Denis \\ [email protected]}
5454
\maketitle
5555
This text and the library are hereby placed in the public domain. This book has been formatted for B5 [176x250] paper using the \LaTeX{} {\em book}

makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ default: libtomfloat.a
66

77
CFLAGS += -Os -Wall -W -I./
88

9-
VERSION=0.01
9+
VERSION=0.02
1010

1111
#default files to install
1212
LIBNAME=libtomfloat.a
@@ -24,7 +24,7 @@ DATAPATH=/usr/share/doc/libtomfloat/pdf
2424
OBJECTS = \
2525
mpf_init.o mpf_clear.o mpf_init_multi.o mpf_clear_multi.o mpf_init_copy.o \
2626
\
27-
mpf_copy.o mpf_exch.o \
27+
mpf_copy.o mpf_exch.o mpf_abs.o mpf_neg.o \
2828
\
2929
mpf_cmp.o mpf_cmp_d.o \
3030
\
@@ -70,7 +70,7 @@ install: libtomfloat.a
7070

7171
clean:
7272
rm -f $(OBJECTS) libtomfloat.a *~ demos/*.o demos/*~ ex1
73-
rm -f float.aux float.dvi float.log float.idx float.lof float.out float.toc
73+
rm -f float.aux float.dvi float.log float.idx float.lof float.out float.toc float.ilg float.ind float.pdf
7474

7575
zipup: clean manual
7676
cd .. ; rm -rf ltf* libtomfloat-$(VERSION) ; mkdir libtomfloat-$(VERSION) ; \

mpf_add.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@ int mpf_add(mp_float *a, mp_float *b, mp_float *c)
1818
mp_float tmp, *other;
1919
long diff;
2020

21+
if (mpf_iszero(a)) {
22+
diff = c->radix;
23+
if ((err = mpf_copy(b, c)) != MP_OKAY) {
24+
return err;
25+
}
26+
return mpf_normalize_to(c, diff);
27+
} else if (mpf_iszero(b)) {
28+
diff = c->radix;
29+
if ((err = mpf_copy(a, c)) != MP_OKAY) {
30+
return err;
31+
}
32+
return mpf_normalize_to(c, diff);
33+
}
34+
2135
if (a->exp < b->exp) {
2236
/* tmp == a normalize to b's exp */
2337
if ((err = mpf_init_copy(a, &tmp)) != MP_OKAY) {

mpf_atan.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,85 @@
1212
*/
1313
#include <tomfloat.h>
1414

15+
/* y = y - (tan(y) - x)/(tan(y+0.1)-tan(x)) */
16+
1517
int mpf_atan(mp_float *a, mp_float *b)
1618
{
19+
mp_float oldval, tmp, tmpx, res, sqr;
20+
int oddeven, ires, err, itts;
21+
long n;
22+
23+
/* ensure -1 <= a <= 1 */
24+
if ((err = mpf_cmp_d(a, -1, &ires)) != MP_OKAY) {
25+
return err;
26+
}
27+
if (ires == MP_LT) {
28+
return MP_VAL;
29+
}
30+
31+
if ((err = mpf_cmp_d(a, 1, &ires)) != MP_OKAY) {
32+
return err;
33+
}
34+
if (ires == MP_GT) {
35+
return MP_VAL;
36+
}
37+
38+
/* easy out if a == 0 */
39+
if (mpf_iszero(a) == MP_YES) {
40+
return mpf_const_d(b, 1);
41+
}
42+
43+
/* now a != 0 */
44+
45+
/* initialize temps */
46+
if ((err = mpf_init_multi(b->radix, &oldval, &tmpx, &tmp, &res, &sqr, NULL)) != MP_OKAY) {
47+
return err;
48+
}
49+
50+
/* initlialize temps */
51+
/* res = 0 */
52+
/* tmpx = 1/a */
53+
if ((err = mpf_inv(a, &tmpx)) != MP_OKAY) { goto __ERR; }
54+
55+
/* sqr = a^2 */
56+
if ((err = mpf_sqr(a, &sqr)) != MP_OKAY) { goto __ERR; }
57+
58+
/* this is the denom counter. Goes up by two per pass */
59+
n = 1;
60+
61+
/* we alternate between adding and subtracting */
62+
oddeven = 0;
63+
64+
/* get number of iterations */
65+
itts = mpf_iterations(b);
66+
67+
while (itts-- > 0) {
68+
if ((err = mpf_copy(&res, &oldval)) != MP_OKAY) { goto __ERR; }
69+
70+
/* compute 1/(2n-1) */
71+
if ((err = mpf_const_d(&tmp, (2*n++ - 1))) != MP_OKAY) { goto __ERR; }
72+
if ((err = mpf_inv(&tmp, &tmp)) != MP_OKAY) { goto __ERR; }
73+
74+
/* now multiply a into tmpx twice */
75+
if ((err = mpf_mul(&tmpx, &sqr, &tmpx)) != MP_OKAY) { goto __ERR; }
76+
77+
/* now multiply the two */
78+
if ((err = mpf_mul(&tmpx, &tmp, &tmp)) != MP_OKAY) { goto __ERR; }
79+
80+
/* now depending on if this is even or odd we add/sub */
81+
oddeven ^= 1;
82+
if (oddeven == 1) {
83+
if ((err = mpf_add(&res, &tmp, &res)) != MP_OKAY) { goto __ERR; }
84+
} else {
85+
if ((err = mpf_sub(&res, &tmp, &res)) != MP_OKAY) { goto __ERR; }
86+
}
87+
88+
if (mpf_cmp(&oldval, &res) == MP_EQ) {
89+
break;
90+
}
91+
}
92+
mpf_exch(&res, b);
93+
__ERR: mpf_clear_multi(&oldval, &tmpx, &tmp, &res, &sqr, NULL);
94+
return err;
95+
1796
}

mpf_const_ln_d.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@
1515
int mpf_const_ln_d(mp_float *a, long b)
1616
{
1717
int err;
18+
19+
/* test input */
20+
if (b < 0) {
21+
return MP_VAL;
22+
}
23+
24+
if (b == 0) {
25+
return mpf_const_d(a, 1);
26+
}
27+
28+
if (b == 1) {
29+
return mpf_const_d(a, 0);
30+
}
31+
1832
if ((err = mpf_const_d(a, b)) != MP_OKAY) {
1933
return err;
2034
}

mpf_cos.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
/* using cos x == \sum_{n=0}^{\infty} ((-1)^n/(2n)!) * x^2n */
1616
int mpf_cos(mp_float *a, mp_float *b)
1717
{
18-
mp_float tmpovern, tmp, tmpx, res, sqr;
18+
mp_float oldval, tmpovern, tmp, tmpx, res, sqr;
1919
int oddeven, err, itts;
2020
long n;
2121
/* initialize temps */
22-
if ((err = mpf_init_multi(b->radix, &tmpx, &tmpovern, &tmp, &res, &sqr, NULL)) != MP_OKAY) {
22+
if ((err = mpf_init_multi(b->radix, &oldval, &tmpx, &tmpovern, &tmp, &res, &sqr, NULL)) != MP_OKAY) {
2323
return err;
2424
}
2525

@@ -40,6 +40,7 @@ int mpf_cos(mp_float *a, mp_float *b)
4040
itts = mpf_iterations(b);
4141

4242
while (itts-- > 0) {
43+
if ((err = mpf_copy(&res, &oldval)) != MP_OKAY) { goto __ERR; }
4344
/* compute 1/(2n)! from 1/(2(n-1))! by multiplying by (1/n)(1/(n+1)) */
4445
if ((err = mpf_const_d(&tmp, ++n)) != MP_OKAY) { goto __ERR; }
4546
if ((err = mpf_inv(&tmp, &tmp)) != MP_OKAY) { goto __ERR; }
@@ -62,8 +63,12 @@ int mpf_cos(mp_float *a, mp_float *b)
6263
} else {
6364
if ((err = mpf_sub(&res, &tmp, &res)) != MP_OKAY) { goto __ERR; }
6465
}
66+
67+
if (mpf_cmp(&res, &oldval) == MP_EQ) {
68+
break;
69+
}
6570
}
6671
mpf_exch(&res, b);
67-
__ERR: mpf_clear_multi(&tmpx, &tmpovern, &tmp, &res, &sqr, NULL);
72+
__ERR: mpf_clear_multi(&oldval, &tmpx, &tmpovern, &tmp, &res, &sqr, NULL);
6873
return err;
6974
}

mpf_exp.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
/* compute b = e^a using e^x == \sum_{n=0}^{\infty} {1 \over n!}x^n */
1717
int mpf_exp(mp_float *a, mp_float *b)
1818
{
19-
mp_float tmpx, tmpovern, tmp, res;
19+
mp_float oldval, tmpx, tmpovern, tmp, res;
2020
int err, itts;
2121
long n;
2222

2323
/* initialize temps */
24-
if ((err = mpf_init_multi(b->radix, &tmpx, &tmpovern, &tmp, &res, NULL)) != MP_OKAY) {
24+
if ((err = mpf_init_multi(b->radix, &oldval, &tmpx, &tmpovern, &tmp, &res, NULL)) != MP_OKAY) {
2525
return err;
2626
}
2727

@@ -36,8 +36,9 @@ int mpf_exp(mp_float *a, mp_float *b)
3636
itts = mpf_iterations(b);
3737

3838
while (itts-- > 0) {
39+
if ((err = mpf_copy(&res, &oldval)) != MP_OKAY) { goto __ERR; }
40+
3941
/* compute 1/n! as 1/(n-1)! * 1/n */
40-
// hack: this won't be portable for n>127
4142
if ((err = mpf_const_d(&tmp, n++)) != MP_OKAY) { goto __ERR; }
4243
if ((err = mpf_inv(&tmp, &tmp)) != MP_OKAY) { goto __ERR; }
4344
if ((err = mpf_mul(&tmp, &tmpovern, &tmpovern)) != MP_OKAY) { goto __ERR; }
@@ -48,10 +49,14 @@ int mpf_exp(mp_float *a, mp_float *b)
4849
/* multiply and sum them */
4950
if ((err = mpf_mul(&tmpovern, &tmpx, &tmp)) != MP_OKAY) { goto __ERR; }
5051
if ((err = mpf_add(&tmp, &res, &res)) != MP_OKAY) { goto __ERR; }
52+
53+
if (mpf_cmp(&oldval, &res) == MP_EQ) {
54+
break;
55+
}
5156
}
5257

5358
mpf_exch(&res, b);
54-
__ERR: mpf_clear_multi(&tmpx, &tmpovern, &tmp, &res, NULL);
59+
__ERR: mpf_clear_multi(&oldval, &tmpx, &tmpovern, &tmp, &res, NULL);
5560
return err;
5661
}
5762

mpf_invsqrt.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
/* using newtons method we have 1/sqrt(x) = Y_{n+1} = y_n * ((3 - xy^2_n)/2) */
1616
int mpf_invsqrt(mp_float *a, mp_float *b)
1717
{
18-
mp_float tmp1, tmp2, const_3;
18+
mp_float oldval, tmp1, tmp2, const_3;
1919
int err, itts;
2020

2121
/* ensure a is not zero or negative */
@@ -27,7 +27,7 @@ int mpf_invsqrt(mp_float *a, mp_float *b)
2727
itts = mpf_iterations(b);
2828

2929
/* init temps */
30-
if ((err = mpf_init_multi(b->radix, &tmp1, &tmp2, &const_3, NULL)) != MP_OKAY) {
30+
if ((err = mpf_init_multi(b->radix, &oldval, &tmp1, &tmp2, &const_3, NULL)) != MP_OKAY) {
3131
return err;
3232
}
3333

@@ -36,13 +36,13 @@ int mpf_invsqrt(mp_float *a, mp_float *b)
3636

3737
/* tmp1 == reasonable guess at sqrt */
3838
if ((err = mpf_copy(a, &tmp1)) != MP_OKAY) { goto __ERR; }
39-
40-
/* negate exponent and halve */
41-
tmp1.radix = b->radix;
42-
if ((err = mp_sqrt(&(tmp1.mantissa), &(tmp1.mantissa))) != MP_OKAY) { goto __ERR; }
43-
if ((err = mpf_normalize(&tmp1)) != MP_OKAY) { goto __ERR; }
39+
mp_rshd(&(tmp1.mantissa), tmp1.mantissa.used>>1);
40+
if ((err = mpf_normalize_to(&tmp1, b->radix)) != MP_OKAY) { goto __ERR; }
4441

4542
while (itts-- > 0) {
43+
/* grap copy of tmp1 for early out */
44+
if ((err = mpf_copy(&tmp1, &oldval)) != MP_OKAY) { goto __ERR; }
45+
4646
/* first tmp2 = y^2 == tmp1^2 */
4747
if ((err = mpf_sqr(&tmp1, &tmp2)) != MP_OKAY) { goto __ERR; }
4848
/* multiply by x, tmp1 * a */
@@ -53,10 +53,15 @@ int mpf_invsqrt(mp_float *a, mp_float *b)
5353
if ((err = mpf_div_2(&tmp2, &tmp2)) != MP_OKAY) { goto __ERR; }
5454
/* multiply by y_n and feedback */
5555
if ((err = mpf_mul(&tmp1, &tmp2, &tmp1)) != MP_OKAY) { goto __ERR; }
56+
57+
/* early out if stable */
58+
if (mpf_cmp(&oldval, &tmp1) == MP_EQ) {
59+
break;
60+
}
5661
}
5762

5863
mpf_exch(&tmp1, b);
59-
__ERR: mpf_clear_multi(&tmp1, &tmp2, &const_3, NULL);
64+
__ERR: mpf_clear_multi(&oldval, &tmp1, &tmp2, &const_3, NULL);
6065
return err;
6166
}
6267

0 commit comments

Comments
 (0)