From 6c3b48ab81272291f481f23d6c92b114d5bd0a77 Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Wed, 5 May 2004 20:37:53 +0000 Subject: [PATCH] added libtomfloat-0.01 --- LICENSE | 3 + TODO | 38 ++++ WARNING | 11 + changes.txt | 3 + demos/ex1.c | 54 +++++ float.ilg | 6 + float.ind | 55 +++++ float.pdf | Bin 0 -> 172888 bytes float.tex | 637 +++++++++++++++++++++++++++++++++++++++++++++++++++++ makefile | 79 +++++++ mpf_abs.c | 23 ++ mpf_acos.c | 17 ++ mpf_add.c | 56 +++++ mpf_add_d.c | 31 +++ mpf_asin.c | 17 ++ mpf_atan.c | 17 ++ mpf_clear.c | 21 ++ mpf_clear_multi.c | 26 +++ mpf_cmp.c | 58 +++++ mpf_cmp_d.c | 30 +++ mpf_const_0.c | 22 ++ mpf_const_1pi.c | 24 ++ mpf_const_1r2.c | 24 ++ mpf_const_2pi.c | 27 +++ mpf_const_2rpi.c | 27 +++ mpf_const_d.c | 35 +++ mpf_const_e.c | 23 ++ mpf_const_l10e.c | 24 ++ mpf_const_l2e.c | 24 ++ mpf_const_le2.c | 20 ++ mpf_const_ln_d.c | 24 ++ mpf_const_pi.c | 32 +++ mpf_const_pi2.c | 24 ++ mpf_const_pi4.c | 27 +++ mpf_const_r2.c | 20 ++ mpf_const_sqrt_d.c | 22 ++ mpf_copy.c | 23 ++ mpf_cos.c | 69 ++++++ mpf_div.c | 37 ++++ mpf_div_2.c | 25 +++ mpf_div_d.c | 31 +++ mpf_exch.c | 20 ++ mpf_exp.c | 57 +++++ mpf_init.c | 20 ++ mpf_init_copy.c | 23 ++ mpf_init_multi.c | 50 +++++ mpf_inv.c | 39 ++++ mpf_invsqrt.c | 62 ++++++ mpf_iterations.c | 26 +++ mpf_ln.c | 17 ++ mpf_mul.c | 24 ++ mpf_mul_2.c | 25 +++ mpf_mul_d.c | 31 +++ mpf_neg.c | 23 ++ mpf_normalize.c | 40 ++++ mpf_normalize_to.c | 19 ++ mpf_pow.c | 36 +++ mpf_sin.c | 78 +++++++ mpf_sqr.c | 23 ++ mpf_sqrt.c | 54 +++++ mpf_sub.c | 51 +++++ mpf_sub_d.c | 31 +++ mpf_tan.c | 39 ++++ tomfloat.h | 105 +++++++++ 64 files changed, 2659 insertions(+) create mode 100644 LICENSE create mode 100644 TODO create mode 100644 WARNING create mode 100644 changes.txt create mode 100644 demos/ex1.c create mode 100644 float.ilg create mode 100644 float.ind create mode 100644 float.pdf create mode 100644 float.tex create mode 100644 makefile create mode 100644 mpf_abs.c create mode 100644 mpf_acos.c create mode 100644 mpf_add.c create mode 100644 mpf_add_d.c create mode 100644 mpf_asin.c create mode 100644 mpf_atan.c create mode 100644 mpf_clear.c create mode 100644 mpf_clear_multi.c create mode 100644 mpf_cmp.c create mode 100644 mpf_cmp_d.c create mode 100644 mpf_const_0.c create mode 100644 mpf_const_1pi.c create mode 100644 mpf_const_1r2.c create mode 100644 mpf_const_2pi.c create mode 100644 mpf_const_2rpi.c create mode 100644 mpf_const_d.c create mode 100644 mpf_const_e.c create mode 100644 mpf_const_l10e.c create mode 100644 mpf_const_l2e.c create mode 100644 mpf_const_le2.c create mode 100644 mpf_const_ln_d.c create mode 100644 mpf_const_pi.c create mode 100644 mpf_const_pi2.c create mode 100644 mpf_const_pi4.c create mode 100644 mpf_const_r2.c create mode 100644 mpf_const_sqrt_d.c create mode 100644 mpf_copy.c create mode 100644 mpf_cos.c create mode 100644 mpf_div.c create mode 100644 mpf_div_2.c create mode 100644 mpf_div_d.c create mode 100644 mpf_exch.c create mode 100644 mpf_exp.c create mode 100644 mpf_init.c create mode 100644 mpf_init_copy.c create mode 100644 mpf_init_multi.c create mode 100644 mpf_inv.c create mode 100644 mpf_invsqrt.c create mode 100644 mpf_iterations.c create mode 100644 mpf_ln.c create mode 100644 mpf_mul.c create mode 100644 mpf_mul_2.c create mode 100644 mpf_mul_d.c create mode 100644 mpf_neg.c create mode 100644 mpf_normalize.c create mode 100644 mpf_normalize_to.c create mode 100644 mpf_pow.c create mode 100644 mpf_sin.c create mode 100644 mpf_sqr.c create mode 100644 mpf_sqrt.c create mode 100644 mpf_sub.c create mode 100644 mpf_sub_d.c create mode 100644 mpf_tan.c create mode 100644 tomfloat.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8f59993 --- /dev/null +++ b/LICENSE @@ -0,0 +1,3 @@ +LibTomFloat is Public Domain. + +-- Tom St Denis diff --git a/TODO b/TODO new file mode 100644 index 0000000..3f009cb --- /dev/null +++ b/TODO @@ -0,0 +1,38 @@ +Still quite a bit todo for LibTomFloat. + +1. The following functions [as of v0.01] have not been implemented (the .C files are present but not populated) + + - mpf_acos + - mpf_asin + - mpf_atan + - mpf_const_1pi [*] + - mpf_const_2pi [*] + - mpf_const_2rpi [*] + - mpf_const_l10e [*] + - mpf_const_l2e [*] + - mpf_const_le2 [*] + - mpf_const_pi [*] + - mpf_const_pi2 [*] + - mpf_const_pi4 [*] + - mpf_ln + - mpf_pow [*] + - Any form of string input/output + +[*] Denotes functions which are written but depend upon incomplete functions to work. + +The critical path lies in two functions. The first is mpf_ln from which I can write mpf_pow and the various constants will function. +The second is mpf_atan from which I can write mpf_const_pi and finish off the missing constants. + +From there it's a matter of adding mpf_asin, mpf_acos and mpf_tan and I have a decent subset of math in there. + +2. Once all of the functions have been written I want to add early-out optimizations to the various series calculations. Right now +they use an arbitrary high count and get accurate results. However, quite a few functions stabalize quickly and do not need so many +iterations. In particular I plan to start on mpf_invsqrt() as it forms the basis of mpf_inv() which is used in mpf_cos() [and other trigs]. + + At the same time I want to add more domain checking (e.g. valid inputs). + +3. Add decent string input/output + +4. More things to the manual. I plan on doing this with every release cycle though. + +5. MSVC makefile diff --git a/WARNING b/WARNING new file mode 100644 index 0000000..1702942 --- /dev/null +++ b/WARNING @@ -0,0 +1,11 @@ +LibTomFloat is a *VERY* new package and is not even fully written yet. Quite a +bit of the functionality is present but will be changing in the near future to allow +for optimizations (e.g. early-outs). + +Please don't use LibTomFloat just yet for any production or fielded system. + +By all means if you wish to test and help find bugs in LibTomFloat give the package a try. + +I do not guarantee the numerical accuracy of this package as of yet. + +You've been warned. diff --git a/changes.txt b/changes.txt new file mode 100644 index 0000000..f77fc00 --- /dev/null +++ b/changes.txt @@ -0,0 +1,3 @@ +May 5th, 2004 v0.01 -- wrote base of LTF + +Anytime v0.00 -- no LTF existed. diff --git a/demos/ex1.c b/demos/ex1.c new file mode 100644 index 0000000..c186421 --- /dev/null +++ b/demos/ex1.c @@ -0,0 +1,54 @@ +#include + +void draw(mp_float *a) +{ + char buf[8192]; + mp_toradix(&(a->mantissa), buf, 10); + printf("%s * 2^%ld\n", buf, a->exp); +} + +int main(void) +{ + mp_float a, b, c, d, e; + mpf_init_multi(96, &a, &b, &c, &d, &e, NULL); + + mpf_const_d(&a, 1); draw(&a); + mpf_const_d(&b, 2); draw(&b); + mpf_const_d(&c, 3); draw(&c); + mpf_const_d(&d, 4); draw(&d); + + mpf_add(&b, &c, &e); printf("2 + 3 == "); draw(&e); + mpf_sub(&b, &c, &e); printf("2 - 3 =="); draw(&e); + mpf_mul(&b, &c, &e); printf("2 * 3 == "); draw(&e); + mpf_div(&b, &c, &e); printf("2 / 3 == "); draw(&e); + printf("\n"); + mpf_invsqrt(&d, &e); printf("1/sqrt(4) == 1/2 == "); draw(&e); + mpf_invsqrt(&c, &e); printf("1/sqrt(3) == "); draw(&e); + mpf_inv(&a, &e); printf("1/1 == "); draw(&e); + mpf_inv(&b, &e); printf("1/2 == "); draw(&e); + mpf_inv(&c, &e); printf("1/3 == "); draw(&e); + mpf_inv(&d, &e); printf("1/4 == "); draw(&e); + printf("\n"); + mpf_const_e(&e); printf("e == "); draw(&e); + mpf_exp(&c, &e); printf("e^3 == "); draw(&e); + mpf_sqrt(&e, &e); printf("sqrt(e^3) == "); draw(&e); + mpf_sqr(&e, &e); printf("sqrt(e^3)^2 == "); draw(&e); + printf("\n"); + mpf_cos(&a, &e); printf("cos(1) == "); draw(&e); + mpf_cos(&b, &e); printf("cos(2) == "); draw(&e); + mpf_cos(&c, &e); printf("cos(3) == "); draw(&e); + mpf_cos(&d, &e); printf("cos(4) == "); draw(&e); + mpf_sin(&a, &e); printf("sin(1) == "); draw(&e); + mpf_sin(&b, &e); printf("sin(2) == "); draw(&e); + mpf_sin(&c, &e); printf("sin(3) == "); draw(&e); + mpf_sin(&d, &e); printf("sin(4) == "); draw(&e); + mpf_tan(&a, &e); printf("tan(1) == "); draw(&e); + mpf_tan(&b, &e); printf("tan(2) == "); draw(&e); + mpf_tan(&c, &e); printf("tan(3) == "); draw(&e); + mpf_tan(&d, &e); printf("tan(4) == "); draw(&e); + printf("\n"); + return 0; +} + + + diff --git a/float.ilg b/float.ilg new file mode 100644 index 0000000..8a4bbbe --- /dev/null +++ b/float.ilg @@ -0,0 +1,6 @@ +This is makeindex, version 2.14 [02-Oct-2002] (kpathsea + Thai support). +Scanning input file float.idx....done (48 entries accepted, 0 rejected). +Sorting entries....done (285 comparisons). +Generating output file float.ind....done (55 lines written, 0 warnings). +Output written in float.ind. +Transcript written in float.ilg. diff --git a/float.ind b/float.ind new file mode 100644 index 0000000..44cddcb --- /dev/null +++ b/float.ind @@ -0,0 +1,55 @@ +\begin{theindex} + + \item exponent, \hyperpage{2} + + \indexspace + + \item mantissa, \hyperpage{2} + \item mp\_cmp, \hyperpage{16} + \item mp\_error\_to\_string, \hyperpage{6} + \item MP\_MEM, \hyperpage{5} + \item MP\_NO, \hyperpage{5} + \item MP\_OKAY, \hyperpage{5} + \item MP\_VAL, \hyperpage{5} + \item MP\_YES, \hyperpage{5} + \item mpf\_abs, \hyperpage{13} + \item mpf\_acos, \hyperpage{18} + \item mpf\_add, \hyperpage{15} + \item mpf\_add\_d, \hyperpage{15} + \item mpf\_asin, \hyperpage{18} + \item mpf\_atan, \hyperpage{18} + \item mpf\_clear, \hyperpage{7} + \item mpf\_clear\_multi, \hyperpage{8} + \item mpf\_cmp\_d, \hyperpage{16} + \item mpf\_const\_0, \hyperpage{11} + \item mpf\_const\_d, \hyperpage{11} + \item mpf\_const\_ln\_d, \hyperpage{11} + \item mpf\_const\_sqrt\_d, \hyperpage{11} + \item mpf\_copy, \hyperpage{9} + \item mpf\_cos, \hyperpage{18} + \item mpf\_div, \hyperpage{15} + \item mpf\_div\_2, \hyperpage{16} + \item mpf\_div\_d, \hyperpage{15} + \item mpf\_exch, \hyperpage{10} + \item mpf\_exp, \hyperpage{17} + \item mpf\_init, \hyperpage{7} + \item mpf\_init\_copy, \hyperpage{8} + \item mpf\_init\_multi, \hyperpage{8} + \item mpf\_inv, \hyperpage{18} + \item mpf\_invsqrt, \hyperpage{18} + \item mpf\_ln, \hyperpage{17} + \item mpf\_mul, \hyperpage{15} + \item mpf\_mul\_2, \hyperpage{16} + \item mpf\_mul\_d, \hyperpage{15} + \item mpf\_neg, \hyperpage{13} + \item mpf\_normalize, \hyperpage{11} + \item mpf\_normalize\_to, \hyperpage{11} + \item mpf\_pow, \hyperpage{17} + \item mpf\_sin, \hyperpage{18} + \item mpf\_sqr, \hyperpage{16} + \item mpf\_sqrt, \hyperpage{18} + \item mpf\_sub, \hyperpage{15} + \item mpf\_sub\_d, \hyperpage{15} + \item mpf\_tan, \hyperpage{18} + +\end{theindex} diff --git a/float.pdf b/float.pdf new file mode 100644 index 0000000000000000000000000000000000000000..aab20d684d868433dc1ab47094fc13295dc094d6 GIT binary patch literal 172888 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 D%LXWO literal 0 HcwPel00001 diff --git a/float.tex b/float.tex new file mode 100644 index 0000000..77c41d9 --- /dev/null +++ b/float.tex @@ -0,0 +1,637 @@ +\documentclass[b5paper]{book} +\usepackage{hyperref} +\usepackage{makeidx} +\usepackage{amssymb} +\usepackage{color} +\usepackage{alltt} +\usepackage{graphicx} +\usepackage{layout} +\def\union{\cup} +\def\intersect{\cap} +\def\getsrandom{\stackrel{\rm R}{\gets}} +\def\cross{\times} +\def\cat{\hspace{0.5em} \| \hspace{0.5em}} +\def\catn{$\|$} +\def\divides{\hspace{0.3em} | \hspace{0.3em}} +\def\nequiv{\not\equiv} +\def\approx{\raisebox{0.2ex}{\mbox{\small $\sim$}}} +\def\lcm{{\rm lcm}} +\def\gcd{{\rm gcd}} +\def\log{{\rm log}} +\def\ord{{\rm ord}} +\def\abs{{\mathit abs}} +\def\rep{{\mathit rep}} +\def\mod{{\mathit\ mod\ }} +\renewcommand{\pmod}[1]{\ ({\rm mod\ }{#1})} +\newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} +\newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} +\def\Or{{\rm\ or\ }} +\def\And{{\rm\ and\ }} +\def\iff{\hspace{1em}\Longleftrightarrow\hspace{1em}} +\def\implies{\Rightarrow} +\def\undefined{{\rm ``undefined"}} +\def\Proof{\vspace{1ex}\noindent {\bf Proof:}\hspace{1em}} +\let\oldphi\phi +\def\phi{\varphi} +\def\Pr{{\rm Pr}} +\newcommand{\str}[1]{{\mathbf{#1}}} +\def\F{{\mathbb F}} +\def\N{{\mathbb N}} +\def\Z{{\mathbb Z}} +\def\R{{\mathbb R}} +\def\C{{\mathbb C}} +\def\Q{{\mathbb Q}} +\definecolor{DGray}{gray}{0.5} +\newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}} +\def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}} +\def\gap{\vspace{0.5ex}} +\makeindex +\begin{document} +\frontmatter +\pagestyle{empty} +\title{LibTomFloat User Manual \\ v0.01} +\author{Tom St Denis \\ tomstdenis@iahu.ca} +\maketitle +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} +macro package. + +\vspace{10cm} + +\begin{flushright}Open Source. Open Academia. Open Minds. + +\mbox{ } + +Tom St Denis, + +Ontario, Canada +\end{flushright} + +\tableofcontents +\listoffigures +\mainmatter +\pagestyle{headings} +\chapter{Introduction} +\section{What is LibTomFloat?} +LibTomFloat is a library of source code that provides multiple precision floating point arithmetic. It allows developers to manipulate floating +point numbers of variable precision. The library was written in portable ISO C source code and depends upon the public domain +LibTomMath package. + +Along with providing the core mathematical operations such as addition and subtraction LibTomFloat also provides various complicated algorithms +such as trigonometry's sine, cosine and tangent operators as well as Calculus's square root, inverse square root, exponential and logarithm +operators. + +LibTomFloat has been written for portability and numerical stability and is not particularly optimized for any given platform. It uses optimal +algorithms for manipulating the mantissa by using LibTomMath and uses numerically stable series for the various trig and calculus functions. + +\section{License} +LibTomFloat is public domain. + +\section{Building LibTomFloat} +LibTomFloat requires version 0.30 or higher of LibTomMath to be installed in order to build. Once LibTomMath is installed building LibTomFloat +is as simple as: + +\begin{alltt} +make +\end{alltt} + +Which will build ``libtomfloat.a'' and along with ``tomfloat.h'' complete an installation of LibTomFloat. You can also use the make target +``install'' to automatically build and copy the files (into *NIX specific) locations. + +\begin{alltt} +make install +\end{alltt} + +\textbf{Note}: LibTomFloat does not use ISO C's native floating point types which means that the standard math library does not have to be +linked in. This also means that LibTomFloat will work decently on platforms that do not have a floating point unit. + + +\section{Purpose of LibTomFloat} +LibTomFloat is as much as an exercise in hardcore math for myself as it is a service to any programmer who needs high precision float point +data types. ISO C provides for fairly reasonable precision floating point data types but is limited. A proper analogy is LibTomFloat solves +ISO C's floating point problems in the same way LibTomMath solves ISO C's integer data type problems. + +A classic example of a good use for large precision floats is long simulations where the numbers are not perfectly stable. A $128$--bit mantissa +(for example) can provide for exceptional precision. + +That and knowing the value of $e$ to 512 bits is fun. + +\section{How the types work} + +\index{mantissa} \index{exponent} +The floating point types are emulated with three components. The \textbf{mantissa}, the \textbf{exponent} and the \textbf{radix}. +The mantissa forms the digits of number being represented. The exponent scales the number to give it a larger range. The radix controls +how many bits there are in the mantissa. The larger the radix the more precise the types become. + +The representation of a number is given by the simple product $m \cdot 2^e$ where $m$ is the mantissa and $e$ the exponent. Numbers are +always normalized such that there are $radix$ bits per mantissa. For example, with $radix = 16$ the number $2$ is represented by +$32768 \cdot 2^{-14}$. A zero is represented by a mantissa of zero and an exponent of one and is a special case. + +The sign flag is a standard ISO C ``long'' which gives it the range $2^{-31} \le e < 2^{31}$ which is considerably large. + +Technically, LibTomFloat does not implement IEEE standard floating point types. The exponent is not normalized and the sign flag does not +count as a bit in the radix. There is also no ``implied'' bit in this system. The mantissa explicitly dictates the digits. + +\chapter{Getting Started with LibTomFloat} +\section{Building Programs} +In order to use libTomFloat you must include ``tomfloat.h'' and link against the appropriate library file (typically +libtomfloat.a). There is no library initialization required and the entire library is thread safe. + +\section{Return Codes} +There are three possible return codes a function may return. + +\index{MP\_OKAY}\index{MP\_YES}\index{MP\_NO}\index{MP\_VAL}\index{MP\_MEM} +\begin{figure}[here!] +\begin{center} +\begin{small} +\begin{tabular}{|l|l|} +\hline \textbf{Code} & \textbf{Meaning} \\ +\hline MP\_OKAY & The function succeeded. \\ +\hline MP\_VAL & The function input was invalid. \\ +\hline MP\_MEM & Heap memory exhausted. \\ +\hline &\\ +\hline MP\_YES & Response is yes. \\ +\hline MP\_NO & Response is no. \\ +\hline +\end{tabular} +\end{small} +\end{center} +\caption{Return Codes} +\end{figure} + +The last two codes listed are not actually ``return'ed'' by a function. They are placed in an integer (the caller must +provide the address of an integer it can store to) which the caller can access. To convert one of the three return codes +to a string use the following function. + +\index{mp\_error\_to\_string} +\begin{alltt} +char *mp_error_to_string(int code); +\end{alltt} + +This will return a pointer to a string which describes the given error code. It will not work for the return codes +MP\_YES and MP\_NO. + +\section{Data Types} + +To better work with LibTomFloat it helps to know what makes up the primary data type within LibTomFloat. + +\begin{alltt} +typedef struct \{ + mp_int mantissa; + long radix, + exp; +\} mp_float; +\end{alltt} + +The mp\_float data type is what all LibTomFloat functions will operate with and upon. The members of the structre are as follows: + +\begin{enumerate} + \item The \textbf{mantissa} variable is a LibTomMath mp\_int that represents the digits of the float. Since it's a mp\_int it can accomodate + any practical range of numbers. + \item The \textbf{radix} variable is the precision desired for the mp\_float in bits. The higher the value the more precise (and slow) the + calculations are. This value must be larger than two and ideally shouldn't be lower than what a ``double'' provides (55-bits of mantissa). + \item The \textbf{exp} variable is the exponent associated with the number. +\end{enumerate} + +\section{Function Organization} + +Many of the functions operate as their LibTomMath counterparts. That is the source operands are on the left and the destination is on the +right. For instance: + +\begin{alltt} +mpf_add(&a, &b, &c); /* c = a + b */ +mpf_mul(&a, &a, &c); /* c = a * a */ +mpf_div(&a, &b, &c); /* c = a / b */ +\end{alltt} + +One major difference (and similar to LibTomPoly) is that the radix of the destination operation controls the radix of the internal computation and +the final result. For instance, if $a$ and $b$ have a $24$--bit mantissa and $c$ has a $96$--bit mantissa then all three operations are performed +with $96$--bits of precision. + +This is non--issue for algorithms such as addition or multiplication but more important for the series calculations such as division, inversion, +square roots, etc. + +All functions normalize the result before returning. + +\section{Initialization} +\subsection{Single Initializers} + +To initialize or clear a single mp\_float use the following two functions. + +\index{mpf\_init} \index{mpf\_clear} +\begin{alltt} +int mpf_init(mp_float *a, long radix); +void mpf_clear(mp_float *a); +\end{alltt} + +mpf\_init will initialize $a$ with the given radix to the default value of zero. mpf\_clear will free the memory used by the +mp\_float. + +\begin{alltt} +int main(void) +\{ + mp_float a; + int err; + + /* initialize a mp_float with a 96-bit mantissa */ + if ((err = mpf_init(&a, 96)) != MP_OKAY) \{ + // error handle + \} + + /* we now have a 96-bit mp_float ready ... do work */ + + /* done */ + mpf_clear(&a); + + return EXIT_SUCCESS; +\} +\end{alltt} + +\subsection{Multiple Initializers} + +To initialize or clear multiple mp\_floats simultaneously use the following two functions. + +\index{mpf\_init\_multi} \index{mpf\_clear\_multi} +\begin{alltt} +int mpf_init_multi(long radix, mp_float *a, ...); +void mpf_clear_multi(mp_float *a, ...); +\end{alltt} + +mpf\_init\_multi will initialize a \textbf{NULL} terminated list of mp\_floats with the same given radix. mpf\_clear\_multi will free +up a \textbf{NULL} terminated list of mp\_floats. + +\begin{alltt} +int main(void) +\{ + mp_float a, b; + int err; + + /* initialize two mp_floats with a 96-bit mantissa */ + if ((err = mpf_init_multi(96, &a, &b, NULL)) != MP_OKAY) \{ + // error handle + \} + + /* we now have two 96-bit mp_floats ready ... do work */ + + /* done */ + mpf_clear_multi(&a, &b, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} + +\subsection{Initialization of Copies} + +In order to initialize an mp\_float and make a copy of a source mp\_float the following function has been provided. + +\index{mpf\_init\_copy} +\begin{alltt} +int mpf_init_copy(mp_float *a, mp_float *b); +\end{alltt} + +This will initialize $b$ and make it a copy of $a$. + +\begin{alltt} +int main(void) +\{ + mp_float a, b; + int err; + + /* initialize a mp_float with a 96-bit mantissa */ + if ((err = mpf_init(&a, 96)) != MP_OKAY) \{ + // error handle + \} + + /* we now have a 96-bit mp_float ready ... do work */ + + /* now make our copy */ + if ((err = mpf_init_copy(&a, &b)) != MP_OKAY) \{ + // error handle + \} + + /* now b is a copy of a */ + + /* done */ + mpf_clear_multi(&a, &b, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} + +\section{Data Movement} +\subsection{Copying} +In order to copy one mp\_float into another mp\_float the following function has been provided. + +\index{mpf\_copy} +\begin{alltt} +int mpf_copy(mp_float *src, mp_float *dest); +\end{alltt} +This will copy the mp\_float from $src$ into $dest$. Note that the final radix of $dest$ will be that of $src$. + +\begin{alltt} +int main(void) +\{ + mp_float a, b; + int err; + + /* initialize two mp_floats with a 96-bit mantissa */ + if ((err = mpf_init_multi(96, &a, &b, NULL)) != MP_OKAY) \{ + // error handle + \} + + /* we now have two 96-bit mp_floats ready ... do work */ + + /* put a into b */ + if ((err = mpf_copy(&a, &b)) != MP_OKAY) \{ + // error handle + \} + + /* done */ + mpf_clear_multi(&a, &b, NULL); + + return EXIT_SUCCESS; +\} +\end{alltt} + +\subsection{Exchange} + +To exchange the contents of two mp\_float data types use this f00. + +\index{mpf\_exch} +\begin{alltt} +void mpf_exch(mp_float *a, mp_float *b); +\end{alltt} + +This will swap the contents of $a$ and $b$. + +\chapter{Basic Operations} +\section{Normalization} + +\subsection{Simple Normalization} +Normalization is not required by the user unless they fiddle with the mantissa on their own. If that's the case you can +use this function. +\index{mpf\_normalize} +\begin{alltt} +int mpf_normalize(mp_float *a); +\end{alltt} +This will fix up the mantissa of $a$ such that the leading bit is one (if the number is non--zero). + +\subsection{Normalize to New Radix} +In order to change the radix of a non--zero number you must call this function. + +\index{mpf\_normalize\_to} +\begin{alltt} +int mpf_normalize_to(mp_float *a, long radix); +\end{alltt} +This will change the radix of $a$ then normalize it accordingly. + +\section{Constants} + +\subsection{Quick Constants} +The following are helpers for various numbers. + +\index{mpf\_const\_0} \index{mpf\_const\_d} \index{mpf\_const\_ln\_d} \index{mpf\_const\_sqrt\_d} +\begin{alltt} +int mpf_const_0(mp_float *a); +int mpf_const_d(mp_float *a, long d); +int mpf_const_ln_d(mp_float *a, long b); +int mpf_const_sqrt_d(mp_float *a, long b); +\end{alltt} + +mpf\_const\_0 will set $a$ to a valid representation of zero. mpf\_const\_d will set $a$ to a valid signed representation of +$d$. mpf\_const\_ln\_d will set $a$ to the natural logarithm of $b$. mpf\_const\_sqrt\_d will set $a$ to the square root of +$b$. + +The next set of constants (fig. \ref{fig:const}) compute the standard constants as defined in ``math.h''. +\begin{figure}[here] +\begin{center} +\begin{tabular}{|l|l|} +\hline \textbf{Function Name} & \textbf{Value} \\ +mpf\_const\_e & $e$ \\ +mpf\_const\_l2e & log$_2(e)$ \\ +mpf\_const\_l10e & log$_{10}(e)$ \\ +mpf\_const\_le2 & ln$(2)$ \\ +mpf\_const\_pi & $\pi$ \\ +mpf\_const\_pi2 & $\pi / 2$ \\ +mpf\_const\_pi4 & $\pi / 4$ \\ +mpf\_const\_1pi & $1 / \pi$ \\ +mpf\_const\_2pi & $2 / \pi$ \\ +mpf\_const\_2rpi & $2 / \sqrt{\pi}$ \\ +mpf\_const\_r2 & ${\sqrt{2}}$ \\ +mpf\_const\_1r2 & $1 / {\sqrt{2}}$ \\ +\hline +\end{tabular} +\end{center} +\caption{LibTomFloat Constants.} +\label{fig:const} +\end{figure} + +All of these functions accept a single input argument. They calculate the constant at run--time using the precision specified in the input +argument. + +\begin{alltt} +int main(void) +\{ + mp_float a; + int err; + + /* initialize a mp_float with a 96-bit mantissa */ + if ((err = mpf_init(&a, 96)) != MP_OKAY) \{ + // error handle + \} + + /* let's find out what the square root of 2 is (approximately ;-)) */ + if ((err = mpf_const_r2(&a)) != MP_OKAY) \{ + // error handle + \} + + /* now a has sqrt(2) to 96-bits of precision */ + + /* done */ + mpf_clear(&a); + + return EXIT_SUCCESS; +\} +\end{alltt} + +\section{Sign Manipulation} +To manipulate the sign of a mp\_float use the following two functions. + +\index{mpf\_abs} \index{mpf\_neg} +\begin{alltt} +int mpf_abs(mp_float *a, mp_float *b); +int mpf_neg(mp_float *a, mp_float *b); +\end{alltt} + +mpf\_abs computes the absolute of $a$ and stores it in $b$. mpf\_neg computes the negative of $a$ and stores it in $b$. Note that the numbers +are normalized to the radix of $b$ before being returned. + +\begin{alltt} +int main(void) +\{ + mp_float a; + int err; + + /* initialize a mp_float with a 96-bit mantissa */ + if ((err = mpf_init(&a, 96)) != MP_OKAY) \{ + // error handle + \} + + /* let's find out what the square root of 2 is (approximately ;-)) */ + if ((err = mpf_const_r2(&a)) != MP_OKAY) \{ + // error handle + \} + + /* now make it negative */ + if ((err = mpf_neg(&a, &a)) != MP_OKAY) \{ + // error handle + \} + + /* done */ + mpf_clear(&a); + + return EXIT_SUCCESS; +\} +\end{alltt} + +\chapter{Basic Algebra} +\section{Algebraic Operators} + +The following four functions provide for basic addition, subtraction, multiplication and division of mp\_float numbers. + +\index{mpf\_add} \index{mpf\_sub} \index{mpf\_mul} \index{mpf\_div} +\begin{alltt} +int mpf_add(mp_float *a, mp_float *b, mp_float *c); +int mpf_sub(mp_float *a, mp_float *b, mp_float *c); +int mpf_mul(mp_float *a, mp_float *b, mp_float *c); +int mpf_div(mp_float *a, mp_float *b, mp_float *c); +\end{alltt} +These functions perform their respective operations on $a$ and $b$ and store the result in $c$. + +\subsection{Additional Interfaces} +In order to make programming easier with the library the following four functions have been provided as well. + +\index{mpf\_add\_d} \index{mpf\_sub\_d} \index{mpf\_mul\_d} \index{mpf\_div\_d} +\begin{alltt} +int mpf_add_d(mp_float *a, long b, mp_float *c); +int mpf_sub_d(mp_float *a, long b, mp_float *c); +int mpf_mul_d(mp_float *a, long b, mp_float *c); +int mpf_div_d(mp_float *a, long b, mp_float *c); +\end{alltt} +These work like the previous four functions except the second argument is a ``long'' type. This allow operations with +mixed mp\_float and integer types (specifically constants) to be performed relatively easy. + +\textit{I will put an example of all op/op\_d functions here...} + +\subsection{Additional Operators} +The next three functions round out the simple algebraic operators. + +\index{mpf\_mul\_2} \index{mpf\_div\_2} \index{mpf\_sqr} +\begin{alltt} +int mpf_mul_2(mp_float *a, mp_float *b); +int mpf_div_2(mp_float *a, mp_float *b); +int mpf_sqr(mp_float *a, mp_float *b); +\end{alltt} + +mpf\_mul\_2 and mpf\_div\_2 multiply (or divide) $a$ by two and store it in $b$. mpf\_sqr squares $a$ and stores it in $b$. mpf\_sqr is +faster than using mpf\_mul for squaring mp\_floats. + +\section{Comparisons} +To compare two mp\_floats the following function can be used. +\index{mp\_cmp} +\begin{alltt} +int mpf_cmp(mp_float *a, mp_float *b); +\end{alltt} +This will compare $a$ to $b$ and return one of the LibTomMath comparison flags. Simply put, if $a$ is larger than $b$ it returns +MP\_GT. If $a$ is smaller than $b$ it returns MP\_LT, otherwise it returns MP\_EQ. The comparison is signed. + +To quickly compare an mp\_float to a ``long'' the following is provided. + +\index{mpf\_cmp\_d} +\begin{alltt} +int mpf_cmp_d(mp_float *a, long b, int *res); +\end{alltt} + +Which compares $a$ to $b$ and stores the result in $res$. This function can fail which is unlike the digit compare from LibTomMath. + +\chapter{Advanced Algebra} +\section{Powers} +\subsection{Exponential} +The following function computes $exp(x)$ otherwise known as $e^x$. + +\index{mpf\_exp} +\begin{alltt} +int mpf_exp(mp_float *a, mp_float *b); +\end{alltt} + +This computes $e^a$ and stores it into $b$. + +\subsection{Power Operator} +The following function computes the generic $a^b$ operation. + +\index{mpf\_pow} +\begin{alltt} +int mpf_pow(mp_float *a, mp_float *b, mp_float *c); +\end{alltt} +This computes $a^b$ and stores the result in $c$. + +\subsection{Natural Logarithm} + +The following function computes the natural logarithm. +\index{mpf\_ln} +\begin{alltt} +int mpf_ln(mp_float *a, mp_float *b); +\end{alltt} +This computes $ln(a)$ and stores the result in $b$. + +\section{Inversion and Roots} + +\subsection{Inverse Square Root} +The following function computes $1 / \sqrt{x}$. + +\index{mpf\_invsqrt} +\begin{alltt} +int mpf_invsqrt(mp_float *a, mp_float *b); +\end{alltt} + +This computes $1 / \sqrt{a}$ and stores the result in $b$. + +\subsection{Inverse} + +The following function computes $1 / x$. +\index{mpf\_inv} +\begin{alltt} +int mpf_inv(mp_float *a, mp_float *b); +\end{alltt} +This computes $1/a$ and stores the result in $b$. + + +\subsection{Square Root} + +The following function computes $\sqrt{x}$. + +\index{mpf\_sqrt} +\begin{alltt} +int mpf_sqrt(mp_float *a, mp_float *b); +\end{alltt} + +This computes $\sqrt{a}$ and stores the result in $b$. + +\section{Trigonometry Functions} +The following functions compute various trigonometric functions. All inputs are assumed to be in radians. + +\index{mpf\_cos} \index{mpf\_sin} \index{mpf\_tan} \index{mpf\_acos} \index{mpf\_asin} \index{mpf\_atan} +\begin{alltt} +int mpf_cos(mp_float *a, mp_float *b); +int mpf_sin(mp_float *a, mp_float *b); +int mpf_tan(mp_float *a, mp_float *b); +int mpf_acos(mp_float *a, mp_float *b); +int mpf_asin(mp_float *a, mp_float *b); +int mpf_atan(mp_float *a, mp_float *b); +\end{alltt} + +These all compute their respective trigonometric function on $a$ and store the result in $b$. The ``a'' prefix stands for ``arc'' or more +commonly known as inverse. + +\input{float.ind} + +\end{document} diff --git a/makefile b/makefile new file mode 100644 index 0000000..b7fb98a --- /dev/null +++ b/makefile @@ -0,0 +1,79 @@ +#GCC makefile for LibTomFloat +# +#Tom St Denis + +default: libtomfloat.a + +CFLAGS += -Os -Wall -W -I./ + +VERSION=0.01 + +#default files to install +LIBNAME=libtomfloat.a +HEADERS=tomfloat.h + +#LIBPATH-The directory for libtomfloat to be installed to. +#INCPATH-The directory to install the header files for libtomfloat. +#DATAPATH-The directory to install the pdf docs. +DESTDIR= +LIBPATH=/usr/lib +INCPATH=/usr/include +DATAPATH=/usr/share/doc/libtomfloat/pdf + + +OBJECTS = \ +mpf_init.o mpf_clear.o mpf_init_multi.o mpf_clear_multi.o mpf_init_copy.o \ +\ +mpf_copy.o mpf_exch.o \ +\ +mpf_cmp.o mpf_cmp_d.o \ +\ +mpf_normalize.o mpf_normalize_to.o mpf_iterations.o \ +\ +mpf_const_0.o mpf_const_1r2.o mpf_const_2rpi.o mpf_const_e.o \ +mpf_const_l2e.o mpf_const_pi.o mpf_const_pi4.o mpf_const_1pi.o \ +mpf_const_2pi.o mpf_const_d.o mpf_const_l10e.o mpf_const_le2.o \ +mpf_const_pi2.o mpf_const_r2.o mpf_const_ln_d.o \ +\ +mpf_mul_2.o mpf_div_2.o mpf_add.o mpf_sub.o mpf_mul.o mpf_sqr.o mpf_div.o \ +mpf_add_d.o mpf_sub_d.o mpf_mul_d.o mpf_div_d.o \ +\ +mpf_invsqrt.o mpf_inv.o mpf_exp.o mpf_sqrt.o mpf_pow.o mpf_ln.o \ +\ +mpf_cos.o mpf_sin.o mpf_tan.o mpf_acos.o mpf_asin.o mpf_atan.o + +libtomfloat.a: $(OBJECTS) + $(AR) $(ARFLAGS) libtomfloat.a $(OBJECTS) + ranlib libtomfloat.a + +ex1: libtomfloat.a demos/ex1.o + $(CC) demos/ex1.o libtomfloat.a -ltommath -o ex1 + +#LTF user manual +mandvi: float.tex + echo "hello" > float.ind + latex float > /dev/null + latex float > /dev/null + makeindex float + latex float > /dev/null + +#LTF user manual [pdf] +manual: mandvi + pdflatex float >/dev/null + rm -f float.aux float.dvi float.log float.idx float.lof float.out float.toc + +install: libtomfloat.a + install -d -g root -o root $(DESTDIR)$(LIBPATH) + install -d -g root -o root $(DESTDIR)$(INCPATH) + install -g root -o root $(LIBNAME) $(DESTDIR)$(LIBPATH) + install -g root -o root $(HEADERS) $(DESTDIR)$(INCPATH) + +clean: + rm -f $(OBJECTS) libtomfloat.a *~ demos/*.o demos/*~ ex1 + rm -f float.aux float.dvi float.log float.idx float.lof float.out float.toc + +zipup: clean manual + cd .. ; rm -rf ltf* libtomfloat-$(VERSION) ; mkdir libtomfloat-$(VERSION) ; \ + cp -R ./libtomfloat/* ./libtomfloat-$(VERSION)/ ; \ + tar -c libtomfloat-$(VERSION)/* | bzip2 -9vvc > ltf-$(VERSION).tar.bz2 ; \ + zip -9 -r ltf-$(VERSION).zip libtomfloat-$(VERSION)/* diff --git a/mpf_abs.c b/mpf_abs.c new file mode 100644 index 0000000..77d362d --- /dev/null +++ b/mpf_abs.c @@ -0,0 +1,23 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_abs(mp_float *a, mp_float *b) +{ + int err; + if ((err = mp_abs((&a->mantissa), &(b->mantissa))) != MP_OKAY) { + return err; + } + b->exp = a->exp; + return mpf_normalize(b); +} diff --git a/mpf_acos.c b/mpf_acos.c new file mode 100644 index 0000000..33b43a9 --- /dev/null +++ b/mpf_acos.c @@ -0,0 +1,17 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_acos(mp_float *a, mp_float *b) +{ +} diff --git a/mpf_add.c b/mpf_add.c new file mode 100644 index 0000000..f5b10c6 --- /dev/null +++ b/mpf_add.c @@ -0,0 +1,56 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_add(mp_float *a, mp_float *b, mp_float *c) +{ + int err; + mp_float tmp, *other; + long diff; + + if (a->exp < b->exp) { + /* tmp == a normalize to b's exp */ + if ((err = mpf_init_copy(a, &tmp)) != MP_OKAY) { + return err; + } + + /* now make tmp.exp == b.exp by dividing tmp by 2^(b.exp - tmp.exp) */ + diff = b->exp - tmp.exp; + tmp.exp = b->exp; + if ((err = mp_div_2d(&(tmp.mantissa), diff, (&tmp.mantissa), NULL)) != MP_OKAY) { goto __TMP; } + + /* other arg */ + other = b; + } else { + /* tmp == b normalize to a's radix */ + if ((err = mpf_init_copy(b, &tmp)) != MP_OKAY) { + return err; + } + + /* now make tmp.exp == a.exp by dividing tmp by 2^(a.exp - tmp.exp) */ + diff = a->exp - tmp.exp; + tmp.exp = a->exp; + if ((err = mp_div_2d(&(tmp.mantissa), diff, (&tmp.mantissa), NULL)) != MP_OKAY) { goto __TMP; } + + /* other arg */ + other = a; + } + + /* perform addition, set the exponent and then normalize */ + if ((err = mp_add(&(tmp.mantissa), &(other->mantissa), &(c->mantissa))) != MP_OKAY) { goto __TMP; } + c->exp = other->exp; + err = mpf_normalize(c); + +__TMP: mpf_clear(&tmp); + return err; +} diff --git a/mpf_add_d.c b/mpf_add_d.c new file mode 100644 index 0000000..c3093bb --- /dev/null +++ b/mpf_add_d.c @@ -0,0 +1,31 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_add_d(mp_float *a, long b, mp_float *c) +{ + int err; + mp_float tmp; + + if ((err = mpf_init(&tmp, c->radix)) != MP_OKAY) { + return err; + } + + if ((err = mpf_const_d(&tmp, b)) != MP_OKAY) { goto __ERR; } + err = mpf_add(a, &tmp, c); + +__ERR: + mpf_clear(&tmp); + return err; +} + diff --git a/mpf_asin.c b/mpf_asin.c new file mode 100644 index 0000000..96be2a1 --- /dev/null +++ b/mpf_asin.c @@ -0,0 +1,17 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_asin(mp_float *a, mp_float *b) +{ +} diff --git a/mpf_atan.c b/mpf_atan.c new file mode 100644 index 0000000..9417066 --- /dev/null +++ b/mpf_atan.c @@ -0,0 +1,17 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_atan(mp_float *a, mp_float *b) +{ +} diff --git a/mpf_clear.c b/mpf_clear.c new file mode 100644 index 0000000..8a8b314 --- /dev/null +++ b/mpf_clear.c @@ -0,0 +1,21 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +void mpf_clear(mp_float *a) +{ + mp_clear(&(a->mantissa)); + a->radix = 0; + a->exp = 0; +} + diff --git a/mpf_clear_multi.c b/mpf_clear_multi.c new file mode 100644 index 0000000..02891d4 --- /dev/null +++ b/mpf_clear_multi.c @@ -0,0 +1,26 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include +#include + +void mpf_clear_multi(mp_float *a, ...) +{ + mp_float* next_mp = a; + va_list args; + va_start(args, a); + while (next_mp != NULL) { + mpf_clear(next_mp); + next_mp = va_arg(args, mp_float*); + } + va_end(args); +} diff --git a/mpf_cmp.c b/mpf_cmp.c new file mode 100644 index 0000000..4a58e34 --- /dev/null +++ b/mpf_cmp.c @@ -0,0 +1,58 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_cmp(mp_float *a, mp_float *b) +{ + int za, zb, sa, sb; + + /* if one is zero than we early out */ + za = mp_iszero(&(a->mantissa)); + sa = a->mantissa.sign; + zb = mp_iszero(&(b->mantissa)); + sb = b->mantissa.sign; + + if (za == MP_YES && zb == MP_NO) { + /* result depends on b */ + if (sb == MP_NEG) { + return MP_GT; + } else { + return MP_LT; + } + } else if (za == MP_NO && zb == MP_YES) { + /* result depends on a */ + if (sa == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare the signs */ + if (sa == MP_NEG && sb == MP_ZPOS) { + return MP_LT; + } else if (sa == MP_ZPOS && sb == MP_NEG) { + return MP_GT; + } + + /* they're both non-zero, the same sign and normalized, compare the exponents */ + if (a->exp > b->exp) { + return (sa == MP_NEG) ? MP_LT : MP_GT; + } else if (a->exp < b->exp) { + return (sa == MP_NEG) ? MP_GT : MP_LT; + } + + /* same exponent and sign, compare mantissa */ + return mp_cmp(&(a->mantissa), &(b->mantissa)); +} + diff --git a/mpf_cmp_d.c b/mpf_cmp_d.c new file mode 100644 index 0000000..401ad25 --- /dev/null +++ b/mpf_cmp_d.c @@ -0,0 +1,30 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_cmp_d(mp_float *a, long b, int *res) +{ + int err; + mp_float tmp; + + if ((err = mpf_init(&tmp, a->radix)) != MP_OKAY) { + return err; + } + + if ((err = mpf_const_d(&tmp, b)) != MP_OKAY) { goto __ERR; } + *res = mpf_cmp(a, &tmp); + +__ERR: + mpf_clear(&tmp); + return err; +} diff --git a/mpf_const_0.c b/mpf_const_0.c new file mode 100644 index 0000000..e6645a8 --- /dev/null +++ b/mpf_const_0.c @@ -0,0 +1,22 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +/* zero defined as 0 * 2^1 */ +int mpf_const_0(mp_float *a) +{ + mp_zero(&(a->mantissa)); + a->exp = 1; + return MP_OKAY; +} + diff --git a/mpf_const_1pi.c b/mpf_const_1pi.c new file mode 100644 index 0000000..fa324aa --- /dev/null +++ b/mpf_const_1pi.c @@ -0,0 +1,24 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_1pi(mp_float *a) +{ + int err; + if ((err = mpf_const_pi(a)) != MP_OKAY) { + return err; + } + return mpf_inv(a, a); +} + /* 1/Pi */ + diff --git a/mpf_const_1r2.c b/mpf_const_1r2.c new file mode 100644 index 0000000..e01b48f --- /dev/null +++ b/mpf_const_1r2.c @@ -0,0 +1,24 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_1r2(mp_float *a) +{ + int err; + if ((err = mpf_const_r2(a)) != MP_OKAY) { + return err; + } + return mpf_inv(a, a); +} + /* 1/sqrt(2) */ + diff --git a/mpf_const_2pi.c b/mpf_const_2pi.c new file mode 100644 index 0000000..7e448bf --- /dev/null +++ b/mpf_const_2pi.c @@ -0,0 +1,27 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_2pi(mp_float *a) +{ + int err; + if ((err = mpf_const_pi(a)) != MP_OKAY) { + return err; + } + if ((err = mpf_inv(a, a)) != MP_OKAY) { + return err; + } + return mpf_mul_2(a, a); +} + /* 2/Pi */ + diff --git a/mpf_const_2rpi.c b/mpf_const_2rpi.c new file mode 100644 index 0000000..a3b4a82 --- /dev/null +++ b/mpf_const_2rpi.c @@ -0,0 +1,27 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_2rpi(mp_float *a) +{ + int err; + if ((err = mpf_const_pi(a)) != MP_OKAY) { + return err; + } + if ((err = mpf_invsqrt(a, a)) != MP_OKAY) { + return err; + } + return mpf_mul_2(a, a); +} + /* 2/sqrt(Pi) */ + diff --git a/mpf_const_d.c b/mpf_const_d.c new file mode 100644 index 0000000..240073f --- /dev/null +++ b/mpf_const_d.c @@ -0,0 +1,35 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_d(mp_float *a, long d) +{ + long x, s; + int err; + + if (d < 0) { + x = -d; + s = MP_NEG; + } else { + x = d; + s = MP_ZPOS; + } + + if ((err = mp_set_int(&(a->mantissa), x)) != MP_OKAY) { + return err; + } + + a->mantissa.sign = s; + a->exp = 0; + return mpf_normalize(a); +} diff --git a/mpf_const_e.c b/mpf_const_e.c new file mode 100644 index 0000000..ed37e2b --- /dev/null +++ b/mpf_const_e.c @@ -0,0 +1,23 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_e(mp_float *a) +{ + int err; + + if ((err = mpf_const_d(a, 1)) != MP_OKAY) { + return err; + } + return mpf_exp(a, a); +} diff --git a/mpf_const_l10e.c b/mpf_const_l10e.c new file mode 100644 index 0000000..85e6c36 --- /dev/null +++ b/mpf_const_l10e.c @@ -0,0 +1,24 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_l10e(mp_float *a) +{ + int err; + if ((err = mpf_const_ln_d(a, 10)) != MP_OKAY) { + return err; + } + return mpf_inv(a, a); +} + /* log_10 e == 1/ln(e) */ + diff --git a/mpf_const_l2e.c b/mpf_const_l2e.c new file mode 100644 index 0000000..a9dfcbc --- /dev/null +++ b/mpf_const_l2e.c @@ -0,0 +1,24 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_l2e(mp_float *a) +{ + int err; + if ((err = mpf_const_ln_d(a, 2)) != MP_OKAY) { + return err; + } + return mpf_inv(a, a); +} + /* log_2 e a.k.a 1/ln2 */ + diff --git a/mpf_const_le2.c b/mpf_const_le2.c new file mode 100644 index 0000000..74eaf12 --- /dev/null +++ b/mpf_const_le2.c @@ -0,0 +1,20 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_le2(mp_float *a) +{ + return mpf_const_ln_d(a, 2); +} + /* log_e 2 */ + diff --git a/mpf_const_ln_d.c b/mpf_const_ln_d.c new file mode 100644 index 0000000..fbe7927 --- /dev/null +++ b/mpf_const_ln_d.c @@ -0,0 +1,24 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_ln_d(mp_float *a, long b) +{ + int err; + if ((err = mpf_const_d(a, b)) != MP_OKAY) { + return err; + } + return mpf_ln(a, a); +} + /* a = ln b */ + diff --git a/mpf_const_pi.c b/mpf_const_pi.c new file mode 100644 index 0000000..8427c6c --- /dev/null +++ b/mpf_const_pi.c @@ -0,0 +1,32 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + + +/* Pi = 4arctan(1) */ +int mpf_const_pi(mp_float *a) +{ + int err; + if ((err = mpf_const_d(a, 1)) != MP_OKAY) { + return err; + } + if ((err = mpf_atan(a, a)) != MP_OKAY) { + return err; + } + if ((err = mpf_mul_2(a, a)) != MP_OKAY) { + return err; + } + return mpf_mul_2(a, a); +} + /* Pi */ + diff --git a/mpf_const_pi2.c b/mpf_const_pi2.c new file mode 100644 index 0000000..ff81852 --- /dev/null +++ b/mpf_const_pi2.c @@ -0,0 +1,24 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_pi2(mp_float *a) +{ + int err; + if ((err = mpf_const_pi(a)) != MP_OKAY) { + return err; + } + return mpf_div_2(a, a); +} + /* Pi/2 */ + diff --git a/mpf_const_pi4.c b/mpf_const_pi4.c new file mode 100644 index 0000000..1fac6e1 --- /dev/null +++ b/mpf_const_pi4.c @@ -0,0 +1,27 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_pi4(mp_float *a) +{ + int err; + if ((err = mpf_const_pi(a)) != MP_OKAY) { + return err; + } + if ((err = mpf_div_2(a, a)) != MP_OKAY) { + return err; + } + return mpf_div_2(a, a); +} + /* Pi/4 */ + diff --git a/mpf_const_r2.c b/mpf_const_r2.c new file mode 100644 index 0000000..afa105e --- /dev/null +++ b/mpf_const_r2.c @@ -0,0 +1,20 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_r2(mp_float *a) +{ + return mpf_const_sqrt_d(a, 2); +} + /* sqrt(2) */ + diff --git a/mpf_const_sqrt_d.c b/mpf_const_sqrt_d.c new file mode 100644 index 0000000..8d4dccd --- /dev/null +++ b/mpf_const_sqrt_d.c @@ -0,0 +1,22 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_const_sqrt_d(mp_float *a, long b) +{ + int err; + if ((err = mpf_const_d(a, b)) != MP_OKAY) { + return err; + } + return mpf_sqrt(a, a); +} diff --git a/mpf_copy.c b/mpf_copy.c new file mode 100644 index 0000000..1befcde --- /dev/null +++ b/mpf_copy.c @@ -0,0 +1,23 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_copy(mp_float *src, mp_float *dest) +{ + if (src == dest) { + return MP_OKAY; + } + dest->radix = src->radix; + dest->exp = src->exp; + return mp_copy(&(src->mantissa), &(dest->mantissa)); +} diff --git a/mpf_cos.c b/mpf_cos.c new file mode 100644 index 0000000..421466c --- /dev/null +++ b/mpf_cos.c @@ -0,0 +1,69 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +/* using cos x == \sum_{n=0}^{\infty} ((-1)^n/(2n)!) * x^2n */ +int mpf_cos(mp_float *a, mp_float *b) +{ + mp_float tmpovern, tmp, tmpx, res, sqr; + int oddeven, err, itts; + long n; + /* initialize temps */ + if ((err = mpf_init_multi(b->radix, &tmpx, &tmpovern, &tmp, &res, &sqr, NULL)) != MP_OKAY) { + return err; + } + + /* initlialize temps */ + /* three start at one, sqr is the square of a */ + if ((err = mpf_const_d(&res, 1)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_const_d(&tmpovern, 1)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_const_d(&tmpx, 1)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_sqr(a, &sqr)) != MP_OKAY) { goto __ERR; } + + /* this is the denom counter. Goes up by two per pass */ + n = 0; + + /* we alternate between adding and subtracting */ + oddeven = 1; + + /* get number of iterations */ + itts = mpf_iterations(b); + + while (itts-- > 0) { + /* compute 1/(2n)! from 1/(2(n-1))! by multiplying by (1/n)(1/(n+1)) */ + if ((err = mpf_const_d(&tmp, ++n)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_inv(&tmp, &tmp)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_mul(&tmpovern, &tmp, &tmpovern)) != MP_OKAY) { goto __ERR; } + /* we do this twice */ + if ((err = mpf_const_d(&tmp, ++n)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_inv(&tmp, &tmp)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_mul(&tmpovern, &tmp, &tmpovern)) != MP_OKAY) { goto __ERR; } + + /* now multiply a into tmpx twice */ + if ((err = mpf_mul(&tmpx, &sqr, &tmpx)) != MP_OKAY) { goto __ERR; } + + /* now multiply the two */ + if ((err = mpf_mul(&tmpx, &tmpovern, &tmp)) != MP_OKAY) { goto __ERR; } + + /* now depending on if this is even or odd we add/sub */ + oddeven ^= 1; + if (oddeven == 1) { + if ((err = mpf_add(&res, &tmp, &res)) != MP_OKAY) { goto __ERR; } + } else { + if ((err = mpf_sub(&res, &tmp, &res)) != MP_OKAY) { goto __ERR; } + } + } + mpf_exch(&res, b); +__ERR: mpf_clear_multi(&tmpx, &tmpovern, &tmp, &res, &sqr, NULL); + return err; +} diff --git a/mpf_div.c b/mpf_div.c new file mode 100644 index 0000000..decef8b --- /dev/null +++ b/mpf_div.c @@ -0,0 +1,37 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_div(mp_float *a, mp_float *b, mp_float *c) +{ + mp_float tmp; + int err; + + /* ensure b is not zero */ + if (mp_iszero(&(b->mantissa)) == MP_YES) { + return MP_VAL; + } + + /* find 1/b */ + if ((err = mpf_init(&tmp, c->radix)) != MP_OKAY) { + return err; + } + if ((err = mpf_inv(b, &tmp)) != MP_OKAY) { goto __ERR; } + + /* now multiply */ + err = mpf_mul(&tmp, a, c); + +__ERR: mpf_clear(&tmp); + return err; +} + diff --git a/mpf_div_2.c b/mpf_div_2.c new file mode 100644 index 0000000..85cf46b --- /dev/null +++ b/mpf_div_2.c @@ -0,0 +1,25 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_div_2(mp_float *a, mp_float *b) +{ + int err; + + /* |b| = |a|/2 */ + if ((err = mp_copy(&(a->mantissa), &(b->mantissa))) != MP_OKAY) { + return err; + } + b->exp = a->exp - 1; + return mpf_normalize(b); +} diff --git a/mpf_div_d.c b/mpf_div_d.c new file mode 100644 index 0000000..0b86248 --- /dev/null +++ b/mpf_div_d.c @@ -0,0 +1,31 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_div_d(mp_float *a, long b, mp_float *c) +{ + int err; + mp_float tmp; + + if ((err = mpf_init(&tmp, c->radix)) != MP_OKAY) { + return err; + } + + if ((err = mpf_const_d(&tmp, b)) != MP_OKAY) { goto __ERR; } + err = mpf_div(a, &tmp, c); + +__ERR: + mpf_clear(&tmp); + return err; +} + diff --git a/mpf_exch.c b/mpf_exch.c new file mode 100644 index 0000000..a0f822b --- /dev/null +++ b/mpf_exch.c @@ -0,0 +1,20 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +void mpf_exch(mp_float *a, mp_float *b) +{ + mp_float tmp; + tmp = *a; *a = *b; *b = tmp; +} + diff --git a/mpf_exp.c b/mpf_exp.c new file mode 100644 index 0000000..f779aeb --- /dev/null +++ b/mpf_exp.c @@ -0,0 +1,57 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + + +/* compute b = e^a using e^x == \sum_{n=0}^{\infty} {1 \over n!}x^n */ +int mpf_exp(mp_float *a, mp_float *b) +{ + mp_float tmpx, tmpovern, tmp, res; + int err, itts; + long n; + + /* initialize temps */ + if ((err = mpf_init_multi(b->radix, &tmpx, &tmpovern, &tmp, &res, NULL)) != MP_OKAY) { + return err; + } + + /* initlialize temps */ + /* all three start at one */ + if ((err = mpf_const_d(&res, 1)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_const_d(&tmpovern, 1)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_const_d(&tmpx, 1)) != MP_OKAY) { goto __ERR; } + n = 1; + + /* get number of iterations */ + itts = mpf_iterations(b); + + while (itts-- > 0) { + /* compute 1/n! as 1/(n-1)! * 1/n */ +// hack: this won't be portable for n>127 + if ((err = mpf_const_d(&tmp, n++)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_inv(&tmp, &tmp)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_mul(&tmp, &tmpovern, &tmpovern)) != MP_OKAY) { goto __ERR; } + + /* compute x^n as x^(n-1) * x */ + if ((err = mpf_mul(&tmpx, a, &tmpx)) != MP_OKAY) { goto __ERR; } + + /* multiply and sum them */ + if ((err = mpf_mul(&tmpovern, &tmpx, &tmp)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_add(&tmp, &res, &res)) != MP_OKAY) { goto __ERR; } + } + + mpf_exch(&res, b); +__ERR: mpf_clear_multi(&tmpx, &tmpovern, &tmp, &res, NULL); + return err; +} + diff --git a/mpf_init.c b/mpf_init.c new file mode 100644 index 0000000..51be263 --- /dev/null +++ b/mpf_init.c @@ -0,0 +1,20 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_init(mp_float *a, long radix) +{ + a->radix = radix; + a->exp = 1; + return mp_init(&(a->mantissa)); +} diff --git a/mpf_init_copy.c b/mpf_init_copy.c new file mode 100644 index 0000000..07acb8f --- /dev/null +++ b/mpf_init_copy.c @@ -0,0 +1,23 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_init_copy(mp_float *a, mp_float *b) +{ + int err; + if ((err = mpf_init(b, a->radix)) != MP_OKAY) { + return err; + } + return mpf_copy(a, b); +} + diff --git a/mpf_init_multi.c b/mpf_init_multi.c new file mode 100644 index 0000000..71762c4 --- /dev/null +++ b/mpf_init_multi.c @@ -0,0 +1,50 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include +#include + +int mpf_init_multi(long radix, mp_float *a, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_float* cur_arg = a; + va_list args; + + va_start(args, a); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mpf_init(cur_arg, radix) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = a; + va_start(clean_args, a); + while (n--) { + mpf_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_float*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_float*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} diff --git a/mpf_inv.c b/mpf_inv.c new file mode 100644 index 0000000..1e1fefa --- /dev/null +++ b/mpf_inv.c @@ -0,0 +1,39 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +/* compute 1/x by (1/sqrt(x))^2 */ +int mpf_inv(mp_float *a, mp_float *b) +{ + int err, sign; + + /* get sign of input */ + sign = a->mantissa.sign; + + /* force to positive */ + a->mantissa.sign = MP_ZPOS; + + /* compute 1/sqrt(a) */ + if ((err = mpf_invsqrt(a, b)) != MP_OKAY) { + return err; + } + + /* square 1/sqrt(a) to get 1/a */ + err = mpf_sqr(b, b); + + /* now restore the sign */ + b->mantissa.sign = a->mantissa.sign = sign; + + return err; +} + diff --git a/mpf_invsqrt.c b/mpf_invsqrt.c new file mode 100644 index 0000000..67963b2 --- /dev/null +++ b/mpf_invsqrt.c @@ -0,0 +1,62 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +/* using newtons method we have 1/sqrt(x) = Y_{n+1} = y_n * ((3 - xy^2_n)/2) */ +int mpf_invsqrt(mp_float *a, mp_float *b) +{ + mp_float tmp1, tmp2, const_3; + int err, itts; + + /* ensure a is not zero or negative */ + if ((mp_iszero(&(a->mantissa)) == MP_YES) || (a->mantissa.sign == MP_NEG)) { + return MP_VAL; + } + + /* get number of iterations */ + itts = mpf_iterations(b); + + /* init temps */ + if ((err = mpf_init_multi(b->radix, &tmp1, &tmp2, &const_3, NULL)) != MP_OKAY) { + return err; + } + + /* const_3 */ + if ((err = mpf_const_d(&const_3, 3)) != MP_OKAY) { goto __ERR; } + + /* tmp1 == reasonable guess at sqrt */ + if ((err = mpf_copy(a, &tmp1)) != MP_OKAY) { goto __ERR; } + + /* negate exponent and halve */ + tmp1.radix = b->radix; + if ((err = mp_sqrt(&(tmp1.mantissa), &(tmp1.mantissa))) != MP_OKAY) { goto __ERR; } + if ((err = mpf_normalize(&tmp1)) != MP_OKAY) { goto __ERR; } + + while (itts-- > 0) { + /* first tmp2 = y^2 == tmp1^2 */ + if ((err = mpf_sqr(&tmp1, &tmp2)) != MP_OKAY) { goto __ERR; } + /* multiply by x, tmp1 * a */ + if ((err = mpf_mul(&tmp2, a, &tmp2)) != MP_OKAY) { goto __ERR; } + /* 3 - xy^2_n == 3 - tmp1 */ + if ((err = mpf_sub(&const_3, &tmp2, &tmp2)) != MP_OKAY) { goto __ERR; } + /* halve it */ + if ((err = mpf_div_2(&tmp2, &tmp2)) != MP_OKAY) { goto __ERR; } + /* multiply by y_n and feedback */ + if ((err = mpf_mul(&tmp1, &tmp2, &tmp1)) != MP_OKAY) { goto __ERR; } + } + + mpf_exch(&tmp1, b); +__ERR: mpf_clear_multi(&tmp1, &tmp2, &const_3, NULL); + return err; +} + diff --git a/mpf_iterations.c b/mpf_iterations.c new file mode 100644 index 0000000..86c7d16 --- /dev/null +++ b/mpf_iterations.c @@ -0,0 +1,26 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_iterations(mp_float *a) +{ + int itts; + + /* always perform at least eight iterations */ + itts = 8; + + /* now add roughly radix */ + itts += a->radix; + + return itts; +} diff --git a/mpf_ln.c b/mpf_ln.c new file mode 100644 index 0000000..66ee656 --- /dev/null +++ b/mpf_ln.c @@ -0,0 +1,17 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_ln(mp_float *a, mp_float *b) +{ +} diff --git a/mpf_mul.c b/mpf_mul.c new file mode 100644 index 0000000..f79daeb --- /dev/null +++ b/mpf_mul.c @@ -0,0 +1,24 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_mul(mp_float *a, mp_float *b, mp_float *c) +{ + int err; + + if ((err = mp_mul(&(a->mantissa), &(b->mantissa), &(c->mantissa))) != MP_OKAY) { + return err; + } + c->exp = a->exp + b->exp; + return mpf_normalize(c); +} diff --git a/mpf_mul_2.c b/mpf_mul_2.c new file mode 100644 index 0000000..4a0ed9e --- /dev/null +++ b/mpf_mul_2.c @@ -0,0 +1,25 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_mul_2(mp_float *a, mp_float *b) +{ + int err; + + /* |b| = 2|a| */ + if ((err = mp_mul_2(&(a->mantissa), &(b->mantissa))) != MP_OKAY) { + return err; + } + + return mpf_normalize(b); +} diff --git a/mpf_mul_d.c b/mpf_mul_d.c new file mode 100644 index 0000000..b74489b --- /dev/null +++ b/mpf_mul_d.c @@ -0,0 +1,31 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_mul_d(mp_float *a, long b, mp_float *c) +{ + int err; + mp_float tmp; + + if ((err = mpf_init(&tmp, c->radix)) != MP_OKAY) { + return err; + } + + if ((err = mpf_const_d(&tmp, b)) != MP_OKAY) { goto __ERR; } + err = mpf_mul(a, &tmp, c); + +__ERR: + mpf_clear(&tmp); + return err; +} + diff --git a/mpf_neg.c b/mpf_neg.c new file mode 100644 index 0000000..a826a22 --- /dev/null +++ b/mpf_neg.c @@ -0,0 +1,23 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_neg(mp_float *a, mp_float *b) +{ + int err; + if ((err = mp_neg((&a->mantissa), &(b->mantissa))) != MP_OKAY) { + return err; + } + b->exp = a->exp; + return mpf_normalize(b); +} diff --git a/mpf_normalize.c b/mpf_normalize.c new file mode 100644 index 0000000..01ef423 --- /dev/null +++ b/mpf_normalize.c @@ -0,0 +1,40 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_normalize(mp_float *a) +{ + long cb, diff; + + /* sanity */ + if (a->radix < 2) { + return MP_VAL; + } + + cb = mp_count_bits(&(a->mantissa)); + if (cb > a->radix) { + diff = cb - a->radix; + a->exp += diff; + return mp_div_2d(&(a->mantissa), diff, &(a->mantissa), NULL); + } else if (cb < a->radix) { + if (mp_iszero(&(a->mantissa)) == MP_YES) { + return mpf_const_0(a); + } else { + diff = a->radix - cb; + a->exp -= diff; + return mp_mul_2d(&(a->mantissa), diff, &(a->mantissa)); + } + } + return MP_OKAY; +} + diff --git a/mpf_normalize_to.c b/mpf_normalize_to.c new file mode 100644 index 0000000..72bdf61 --- /dev/null +++ b/mpf_normalize_to.c @@ -0,0 +1,19 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_normalize_to(mp_float *a, long radix) +{ + a->radix = radix; + return mpf_normalize(a); +} diff --git a/mpf_pow.c b/mpf_pow.c new file mode 100644 index 0000000..dd70883 --- /dev/null +++ b/mpf_pow.c @@ -0,0 +1,36 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +/* we have e^x, so why not write a^b as e^(lna * b) ;-) w00t w00t */ +int mpf_pow(mp_float *a, mp_float *b, mp_float *c) +{ + mp_float exponent; + int err; + + if ((err = mpf_init(&exponent, c->radix)) != MP_OKAY) { + return err; + } + + /* get ln of a */ + if ((err = mpf_ln(a, &exponent)) != MP_OKAY) { goto __ERR; } + + /* multiply it by b */ + if ((err = mpf_mul(&exponent, b, &exponent)) != MP_OKAY) { goto __ERR; } + + /* now evaluate it */ + err = mpf_exp(&exponent, c); + +__ERR: mpf_clear(&exponent); + return err; +} diff --git a/mpf_sin.c b/mpf_sin.c new file mode 100644 index 0000000..e5d672d --- /dev/null +++ b/mpf_sin.c @@ -0,0 +1,78 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +/* using sin x == \sum_{n=0}^{\infty} ((-1)^n/(2n+1)!) * x^(2n+1) */ +int mpf_sin(mp_float *a, mp_float *b) +{ + mp_float tmpovern, tmp, tmpx, res, sqr; + int oddeven, err, itts; + long n; + + /* initialize temps */ + if ((err = mpf_init_multi(b->radix, &tmpx, &tmpovern, &tmp, &res, &sqr, NULL)) != MP_OKAY) { + return err; + } + + /* initlialize temps */ + /* this is the 1/n! which starts at 1 */ + if ((err = mpf_const_d(&tmpovern, 1)) != MP_OKAY) { goto __ERR; } + + /* the square of the input, used to save multiplications later */ + if ((err = mpf_sqr(a, &sqr)) != MP_OKAY) { goto __ERR; } + + /* tmpx starts at the input, so we copy and normalize */ + if ((err = mpf_copy(a, &tmpx)) != MP_OKAY) { goto __ERR; } + tmpx.radix = b->radix; + if ((err = mpf_normalize(&tmpx)) != MP_OKAY) { goto __ERR; } + + /* the result starts off at a as we skip a term in the series */ + if ((err = mpf_copy(&tmpx, &res)) != MP_OKAY) { goto __ERR; } + + /* this is the denom counter. Goes up by two per pass */ + n = 1; + + /* we alternate between adding and subtracting */ + oddeven = 1; + + /* get number of iterations */ + itts = mpf_iterations(b); + + while (itts-- > 0) { + /* compute 1/(2n)! from 1/(2(n-1))! by multiplying by (1/n)(1/(n+1)) */ + if ((err = mpf_const_d(&tmp, ++n)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_inv(&tmp, &tmp)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_mul(&tmpovern, &tmp, &tmpovern)) != MP_OKAY) { goto __ERR; } + /* we do this twice */ + if ((err = mpf_const_d(&tmp, ++n)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_inv(&tmp, &tmp)) != MP_OKAY) { goto __ERR; } + if ((err = mpf_mul(&tmpovern, &tmp, &tmpovern)) != MP_OKAY) { goto __ERR; } + + /* now multiply sqr into tmpx */ + if ((err = mpf_mul(&tmpx, &sqr, &tmpx)) != MP_OKAY) { goto __ERR; } + + /* now multiply the two */ + if ((err = mpf_mul(&tmpx, &tmpovern, &tmp)) != MP_OKAY) { goto __ERR; } + + /* now depending on if this is even or odd we add/sub */ + oddeven ^= 1; + if (oddeven == 1) { + if ((err = mpf_add(&res, &tmp, &res)) != MP_OKAY) { goto __ERR; } + } else { + if ((err = mpf_sub(&res, &tmp, &res)) != MP_OKAY) { goto __ERR; } + } + } + mpf_exch(&res, b); +__ERR: mpf_clear_multi(&tmpx, &tmpovern, &tmp, &res, &sqr, NULL); + return err; +} diff --git a/mpf_sqr.c b/mpf_sqr.c new file mode 100644 index 0000000..4250b8e --- /dev/null +++ b/mpf_sqr.c @@ -0,0 +1,23 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_sqr(mp_float *a, mp_float *b) +{ + int err; + if ((err = mp_sqr(&(a->mantissa), &(b->mantissa))) != MP_OKAY) { + return err; + } + b->exp = 2 * a->exp; + return mpf_normalize(b); +} diff --git a/mpf_sqrt.c b/mpf_sqrt.c new file mode 100644 index 0000000..ddfb4b8 --- /dev/null +++ b/mpf_sqrt.c @@ -0,0 +1,54 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +/* compute using sqrt(x) = y_{n+1} = 0.5 * (y_{n} + x/y_{n}) */ +int mpf_sqrt(mp_float *a, mp_float *b) +{ + mp_float tmp, res; + int err, itts; + + /* make sure it's positive */ + if (a->mantissa.sign == MP_NEG) { + return MP_VAL; + } + + /* let's roll */ + if ((err = mpf_init_multi(b->radix, &tmp, &res, NULL)) != MP_OKAY) { + return err; + } + + /* get copy of a and make reasonable guestimte towards the sqrt */ + if ((err = mpf_copy(a, &res)) != MP_OKAY) { goto __ERR; } + if ((err = mp_sqrt(&res.mantissa, &res.mantissa)) != MP_OKAY) { goto __ERR; } + res.exp = res.exp / 2; + res.radix = b->radix; + if ((err = mpf_normalize(&res)) != MP_OKAY) { goto __ERR; } + + /* number of iterations */ + itts = mpf_iterations(b); + + while (itts--) { + /* compute x/res */ + if ((err = mpf_div(a, &res, &tmp)) != MP_OKAY) { goto __ERR; } + /* res + x/res */ + if ((err = mpf_add(&res, &tmp, &res)) != MP_OKAY) { goto __ERR; } + /* 0.5 * (res + x/res) */ + if ((err = mpf_div_2(&res, &res)) != MP_OKAY) { goto __ERR; } + } + + mpf_exch(&res, b); +__ERR: mpf_clear_multi(&tmp, &res, NULL); + return err; +} + diff --git a/mpf_sub.c b/mpf_sub.c new file mode 100644 index 0000000..cf819c1 --- /dev/null +++ b/mpf_sub.c @@ -0,0 +1,51 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_sub(mp_float *a, mp_float *b, mp_float *c) +{ + int err; + mp_float tmp; + long diff; + + if (a->exp < b->exp) { + /* tmp == a normalize to b's exp */ + if ((err = mpf_init_copy(a, &tmp)) != MP_OKAY) { + return err; + } + + /* now make tmp.exp == b.exp by dividing tmp by 2^(b.exp - tmp.exp) */ + diff = b->exp - tmp.exp; + tmp.exp = b->exp; + if ((err = mp_div_2d(&(tmp.mantissa), diff, (&tmp.mantissa), NULL)) != MP_OKAY) { goto __TMP; } + if ((err = mp_sub(&(tmp.mantissa), &(b->mantissa), &(c->mantissa))) != MP_OKAY) { goto __TMP; } + c->exp = b->exp; + } else { + /* tmp == b normalize to a's radix */ + if ((err = mpf_init_copy(b, &tmp)) != MP_OKAY) { + return err; + } + + /* now make tmp.exp == a.exp by dividing tmp by 2^(a.exp - tmp.exp) */ + diff = a->exp - tmp.exp; + tmp.exp = a->exp; + if ((err = mp_div_2d(&(tmp.mantissa), diff, (&tmp.mantissa), NULL)) != MP_OKAY) { goto __TMP; } + if ((err = mp_sub(&(a->mantissa), &(tmp.mantissa), &(c->mantissa))) != MP_OKAY) { goto __TMP; } + c->exp = a->exp; + } + + err = mpf_normalize(c); + +__TMP: mpf_clear(&tmp); + return err; +} diff --git a/mpf_sub_d.c b/mpf_sub_d.c new file mode 100644 index 0000000..7c8560d --- /dev/null +++ b/mpf_sub_d.c @@ -0,0 +1,31 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +int mpf_sub_d(mp_float *a, long b, mp_float *c) +{ + int err; + mp_float tmp; + + if ((err = mpf_init(&tmp, c->radix)) != MP_OKAY) { + return err; + } + + if ((err = mpf_const_d(&tmp, b)) != MP_OKAY) { goto __ERR; } + err = mpf_sub(a, &tmp, c); + +__ERR: + mpf_clear(&tmp); + return err; +} + diff --git a/mpf_tan.c b/mpf_tan.c new file mode 100644 index 0000000..50c7fdf --- /dev/null +++ b/mpf_tan.c @@ -0,0 +1,39 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#include + +/* tan = sin/cos, prolly fix this up later */ +int mpf_tan(mp_float *a, mp_float *b) +{ + int err; + mp_float tmp; + + /* get cos of a */ + if ((err = mpf_init(&tmp, b->radix)) != MP_OKAY) { + return err; + } + if ((err = mpf_cos(a, &tmp)) != MP_OKAY) { goto __ERR; } + + /* now make it upside down ;-) (this should catch domain errors too) */ + if ((err = mpf_inv(&tmp, &tmp)) != MP_OKAY) { goto __ERR; } + + /* put sin in b */ + if ((err = mpf_sin(a, b)) != MP_OKAY) { goto __ERR; } + + /* multiply the two and we done */ + err = mpf_mul(b, &tmp, b); + +__ERR: mpf_clear(&tmp); + return err; +} + diff --git a/tomfloat.h b/tomfloat.h new file mode 100644 index 0000000..a7c3af2 --- /dev/null +++ b/tomfloat.h @@ -0,0 +1,105 @@ +/* LibTomFloat, multiple-precision floating-point library + * + * LibTomFloat is a library that provides multiple-precision + * floating-point artihmetic as well as trigonometric functionality. + * + * This library requires the public domain LibTomMath to be installed. + * + * This library is free for all purposes without any express + * gurantee it works + * + * Tom St Denis, tomstdenis@iahu.ca, http://float.libtomcrypt.org + */ +#ifndef TF_H_ +#define TF_H_ + +#include + +/* this is mp_float type */ +typedef struct { + mp_int mantissa; + long radix, /* how many bits for mantissa */ + exp; /* current exponent, e.g. mantissa * 2^exp == number */ +} mp_float; + +/* initializers */ +int mpf_init(mp_float *a, long radix); +void mpf_clear(mp_float *a); + +int mpf_init_multi(long radix, mp_float *a, ...); +void mpf_clear_multi(mp_float *a, ...); + +int mpf_init_copy(mp_float *a, mp_float *b); + +int mpf_copy(mp_float *src, mp_float *dest); +void mpf_exch(mp_float *a, mp_float *b); + +/* maintainers */ +int mpf_normalize(mp_float *a); +int mpf_normalize_to(mp_float *a, long radix); +int mpf_iterations(mp_float *a); + +/* constants */ +int mpf_const_0(mp_float *a); /* valid zero */ +int mpf_const_d(mp_float *a, long d); /* valid d */ +int mpf_const_ln_d(mp_float *a, long b); /* a = ln(b) */ +int mpf_const_sqrt_d(mp_float *a, long b); /* a = sqrt(b); */ + +/* math constants as they appear in math.h */ +int mpf_const_e(mp_float *a); /* e */ +int mpf_const_l2e(mp_float *a); /* log_2 e */ +int mpf_const_l10e(mp_float *a); /* log_10 e */ +int mpf_const_le2(mp_float *a); /* log_e 2 */ +int mpf_const_pi(mp_float *a); /* Pi */ +int mpf_const_pi2(mp_float *a); /* Pi/2 */ +int mpf_const_pi4(mp_float *a); /* Pi/4 */ +int mpf_const_1pi(mp_float *a); /* 1/Pi */ +int mpf_const_2pi(mp_float *a); /* 2/Pi */ +int mpf_const_2rpi(mp_float *a); /* 2/sqrt(Pi) */ +int mpf_const_r2(mp_float *a); /* sqrt(2) */ +int mpf_const_1r2(mp_float *a); /* 1/sqrt(2) */ + +/* sign operators */ +int mpf_abs(mp_float *a, mp_float *b); /* absolute */ +int mpf_neg(mp_float *a, mp_float *b); /* negation */ + +/* basic math */ +int mpf_mul_2(mp_float *a, mp_float *b); /* b = 2a */ +int mpf_div_2(mp_float *a, mp_float *b); /* b = a/2 */ +int mpf_add(mp_float *a, mp_float *b, mp_float *c); /* c = a + b */ +int mpf_sub(mp_float *a, mp_float *b, mp_float *c); /* c = a - b */ +int mpf_mul(mp_float *a, mp_float *b, mp_float *c); /* c = a * b */ +int mpf_div(mp_float *a, mp_float *b, mp_float *c); /* c = a / b */ +int mpf_sqr(mp_float *a, mp_float *b); /* b = a^2 */ + +int mpf_add_d(mp_float *a, long b, mp_float *c); /* c = a + b */ +int mpf_sub_d(mp_float *a, long b, mp_float *c); /* c = a - b */ +int mpf_mul_d(mp_float *a, long b, mp_float *c); /* c = a * b */ +int mpf_div_d(mp_float *a, long b, mp_float *c); /* c = a / b */ + +/* compares */ +int mpf_cmp(mp_float *a, mp_float *b); +int mpf_cmp_d(mp_float *a, long b, int *res); +#define mpf_iszero(a) mp_iszero(&((a)->mantissa)) + +/* Algebra */ +int mpf_exp(mp_float *a, mp_float *b); /* b = e^a */ +int mpf_pow(mp_float *a, mp_float *b, mp_float *c); /* c = a^b */ +int mpf_ln(mp_float *a, mp_float *b); /* b = ln a */ +int mpf_invsqrt(mp_float *a, mp_float *b); /* b = 1/sqrt(a) */ +int mpf_inv(mp_float *a, mp_float *b); /* b = 1/a */ +int mpf_sqrt(mp_float *a, mp_float *b); /* b = sqrt(a) */ + +/* Trig */ +int mpf_cos(mp_float *a, mp_float *b); /* b = cos(a) */ +int mpf_sin(mp_float *a, mp_float *b); /* b = sin(a) */ +int mpf_tan(mp_float *a, mp_float *b); /* b = tan(a) */ +int mpf_acos(mp_float *a, mp_float *b); /* b = acos(a) */ +int mpf_asin(mp_float *a, mp_float *b); /* b = asin(a) */ +int mpf_atan(mp_float *a, mp_float *b); /* b = atan(a) */ + +/* ASCII <=> mp_float conversions */ +char *mpf_to_string(mp_float *a, mp_digit radix); +int mpf_from_string(mp_float *a, const char *str, mp_digit radix); + +#endif -- 2.11.4.GIT