1 % lias.lhs - Language Independent Arithmetic Standard in Haskell
3 % @(#)LIAS.lhs 1.11 dated 92/12/07 at 15:01:23
5 \documentstyle[a4wide,11pt,times]{article}
7 \title{Haskell and the Language Independent Arithmetic Standard}
9 National Physical Laboratory\\
10 Teddington, TW11 0LW, UK.\\
11 {\tt ndn@seg.npl.co.uk}}
13 % Some macros lifted from elsewhere to make this more standalone.
17 % \prog{foo} sets its argument in typewriter font.
18 \def\prog#1{\ifmmode\mbox{\tt #1}\else{\tt #1}\fi}
20 % NEWVERBATIM (from iso.sty)
22 % \newverbatim{foo} creates a new environment, foo, which behaves exactly
23 % like the verbatim environment except that it is delimited by
24 % \begin{foo} ... \end{foo}.
25 % See the VERBATIM section of latex.tex for the inspiration behind this.
27 \def\newverbatim#1{\expandafter\def\csname #1\endcsname{%
28 \@verbatim \frenchspacing\@vobeyspaces \csname @x#1verbatim\endcsname}
29 \expandafter\let\csname end#1\endcsname=\endtrivlist
32 \begingroup \catcode `|=0 \catcode `[= 1
33 \catcode`]=2 \catcode `\{=12 \catcode `\}=12
35 |gdef|new@xverbatim#1[
36 |expandafter|def|csname @x#1verbatim|endcsname##1\end{#1}[##1|end[#1]]]
42 % \lias{id} sets an identifier in LIAS font (italic)
43 \def\lias#1{\mbox{\it #1}}
45 % \liass{id}{sub} sets the identifier in LIAS font, with the given
47 \def\liass#1#2{\mbox{$\lias{#1}_{#2}$}}
49 % \liasss{id}{sub}{sup} sets the identifier in LIAS font, with the
50 % subscript and superscript.
51 \def\liasss#1#2#3{\mbox{$\lias{#1}_{#2}^{#3}$}}
56 \section*{Introduction}
58 Haskell~\cite{hudak} is intended as an ``industrial strength''
59 functional programming language and, in partial fulfillment of that
60 aim, includes a rich set of numeric types and operators.
61 However, the semantics of numeric operations are rather imprecise, so
62 that determining the accuracy of numerical analysis programs is impossible
63 in Haskell, limiting its applicability.
64 The Language Independent Arithmetic Standard (LIAS)~\cite{lias}
65 defines the behaviour of numerical operations precisely, yet flexibly
66 enough that it is compatible with virtually all major arithmetic
67 implementations including, for example IEEE~754~\cite{ieee754}.
69 This report examines the extent to which Haskell and LIAS are compatible,
70 provides a model implementation of LIAS in Haskell, and recommends a
71 small addition to Haskell to improve compatibility.
72 The intention is to improve the portability of programs, both between
73 Haskell implementations and between Haskell and other LIAS-compliant
77 \section{Compatibility between Haskell and LIAS}
79 \subsection{Denormalised numbers}
81 Parameters for LIAS are all available in Haskell, with the exception of
82 \lias{denorm}, so few problems in principle.
85 Haskell implementations tend to use arithmetic of underlying system, so
86 extent to which accuracy complies depends on that of underlying system.
88 \subsection{Notification}
90 Semantics of overflow etc are ``undefined'' so demanding notification is
92 {\em Check what systems actually do.}
95 Haskell provides a class \prog{Integral}, whose members are integer
97 In particular, \prog{Integer} is the type of arbitrary-precision
98 integers, and \prog{Int} is a type of fixed-precision integers with
99 range at least $[-2^{29} + 1, 2^{29} - 1]$ and closed under
101 Implementations are at liberty provide other integer types.
103 Both \prog{Integer} and \prog{Int} should comply with LIAS, with the
104 exception of notifications, as described in Section~\ref{notification}.
106 \subsection{Floating point}
107 Haskell provides a class \prog{RealFloat}, whose members are real (as
108 opposed to complex) floating point numbers.
109 In particular, \prog{Float} and \prog{Double} are supposed to
110 be at least equal in range and precision to IEEE single and double
111 precision respectively.
112 Implementations are at liberty provide other floating point types.
114 Both \prog{Float} and \prog{Double} should comply with LIAS, with the
115 exceptions of notifications, as described in Section~\ref{notification},
116 and \lias{denorm}, as described in Section~\ref{denorm}.
119 \section{LIAS in Haskell}
121 This section provides a model implementation of LIAS in Haskell.
122 Many of the required parameters and functions already exist, in which
123 case this section just describes how to obtain them in Haskell.
124 Others are not part of the standard language, and code is given to
127 The section begins with the module header giving the module name and
128 exported identifiers.
133 > emax, emin, denorm,
134 > fmax, fminN, fmin, epsilon,
135 > signf, succf, predf, ulpf, truncf, roundf, fractpart
141 \subsection{Integers}
142 The LIAS parameters are: \lias{minint}, \lias{maxint} and \lias{bounded}.
143 Whether an integer type is bounded or not is part of the language
144 definition, so this parameter is not available to the user in Haskell.
145 The minimum and maximum parameters are available for the \prog{Int}
146 type, and are accessed as follows:
148 \lias{minint} \= \prog{minInt} \kill
149 \lias{minint} \> \prog{minInt} \\
150 \lias{maxint} \> \prog{maxInt} (\prog{= -minInt})
152 Note that the Haskell Report (Section 6.8.2) states that
153 \prog{maxInt = -minInt}, which is compatible with LIAS.
155 All the integer operations required by LIAS are available in Haskell,
156 and are accessed as described in the table below:
158 mmmmmmmmmmmmmmm \= mmmmmmmmmm \= \kill
159 \liass{add}{I} \> \prog{x + y} \\
160 \liass{sub}{I} \> \prog{x - y} \\
161 \liass{mul}{I} \> \prog{x * y} \\
162 \liass{div}{I} \> \prog{x `div` y} (round to $-\infty$) \\
163 \> \prog{x `quot` y} (round to 0) \\
164 \liass{rem}{I} \> \prog{x `mod` y} (round to $-\infty$) \\
165 \> \prog{x `rem` y} (round to 0) \\
166 \liass{mod}{I} \> \prog{x `mod` y} (this is \liasss{mod}{I}{1}) \\
167 \liass{neg}{I} \> \prog{negate x} \\
168 \liass{abs}{I} \> \prog{abs x} \\
169 \liass{eq}{I} \> \prog{x == y} \\
170 \liass{neq}{I} \> \prog{x /= y} \\
171 \liass{lss}{I} \> \prog{x < y} \\
172 \liass{leq}{I} \> \prog{x <= y} \\
173 \liass{gtr}{I} \> \prog{x > y} \\
174 \liass{geq}{I} \> \prog{x >= y}
176 The table shows that Haskell provides integer division with rounding
177 towards $-\infty$ and with rounding towards 0.
179 \subsection{Floating point}
180 Haskell provides all the parameters for floating point numbers, except
182 The available parameters are determined as follows:
184 \lias{emax} \= fst (floatRange x) \= \prog{Int} \kill
185 \lias{r} \> floatRadix x \> \prog{Integer} \\
186 \lias{p} \> floatDigits x \> \prog{Int} \\
187 \lias{emax} \> fst (floatRange x) \> \prog{Int} \\
188 \lias{emin} \> snd (floatRange x) \> \prog{Int}
190 In the table, \prog{x} is an expression of the type for which the
191 parameter is required.
192 For example, \prog{floatRadix (1.0 :: Float)} would give the radix of
193 the \prog{Float} type.
194 The alternative to this mechanism is to provide a separate set of
195 identifiers for each floating point type.
197 For convenience, we provide Haskell identifiers for \lias{emax} and
201 > emax, emin :: (RealFloat a) => a -> Int
202 > emax x = snd (floatRange x)
203 > emin x = fst (floatRange x)
207 The derived constants require some coding as follows:
210 > fmax, fminN, fminD, fmin, epsilon :: (RealFloat a) => a -> a
212 > fmax x = encodeFloat (floatRadix x ^ floatDigits x - 1)
213 > (emax x - floatDigits x)
215 > fminN x = encodeFloat 1 (emin x - 1)
217 > fminD x = encodeFloat 1 (emin x - floatDigits x)
219 > fmin x = if denorm x then fminD x else fminN x
221 > epsilon x = encodeFloat 1 (1 - floatDigits x)
225 The definition of \lias{denorm} assumes that the implementation gives
227 The Haskell Report leaves behaviour on underflow undefined, which
228 makes this definition less than satisfactory and suggests that
229 \prog{denorm} should be part of the language.
232 > denorm :: (RealFloat a) => a -> Bool
233 > denorm x = fminN x / fromInteger (floatRadix x) /= 0
237 The floating point operations are listed below, with the syntax for
239 The operations marked ``$\dagger$'' are not part of Haskell and are
240 defined later in the LIAS module.
242 mmmmmmmmmmmmmmm \= mmmmmmmmmm \= \kill
243 \liass{add}{F} \> \prog{x + y} \\
244 \liass{sub}{F} \> \prog{x - y} \\
245 \liass{mul}{F} \> \prog{x * y} \\
246 \liass{div}{F} \> \prog{x / y} \\
247 \liass{neg}{F} \> \prog{negate x} \\
248 \liass{abs}{F} \> \prog{abs x} \\
249 \liass{sqrt}{F} \> \prog{sqrt x} \\
250 \liass{sign}{F} \> \prog{signf x} \> $\dagger$ \\
251 \liass{exponent}{F} \> \prog{exponent x} \\
252 \liass{fraction}{F} \> \prog{significand x} \\
253 \liass{scale}{F} \> \prog{scaleFloat n x} \\
254 \liass{succ}{F} \> \prog{succf x} \> $\dagger$ \\
255 \liass{pred}{F} \> \prog{predf x} \> $\dagger$ \\
256 \liass{ulp}{F} \> \prog{ulpf x} \> $\dagger$ \\
257 \liass{trunc}{F} \> \prog{truncf x n} \> $\dagger$ \\
258 \liass{round}{F} \> \prog{roundf x n} \> $\dagger$ \\
259 \liass{intpart}{F} \> \prog{truncate x} \\
260 \liass{fractpart}{F} \> \prog{snd (properFraction x)} \\
261 \liass{eq}{F} \> \prog{x == y} \\
262 \liass{neq}{F} \> \prog{x /= y} \\
263 \liass{lss}{F} \> \prog{x < y} \\
264 \liass{leq}{F} \> \prog{x <= y} \\
265 \liass{gtr}{F} \> \prog{x > y} \\
266 \liass{geq}{F} \> \prog{x >= y}
269 The code below provides definitions of the operations marked ``$\dagger$''
270 and, for convenience, a definition of \liass{fractpart}{F}.
274 > signf :: (RealFloat a) => a -> a
275 > signf x | x >= 0 = 1
280 \prog{floatRadixf} is a useful utility function which gives the floating
281 point radix as a member of the class \prog{RealFloat}.
284 > floatRadixf :: (RealFloat a) => a -> a
285 > floatRadixf x = fromInteger (floatRadix x)
291 > succf, predf :: (RealFloat a) => a -> a
292 > succf x | x == 0 = fmin x
293 > | x == -(fmin x) = 0
294 > | True = encodeFloat (m + 1) n
296 > (m, n) = decodeFloat x
298 > predf x = - succf (- x)
304 > ulpf :: (RealFloat a) => a -> a
305 > ulpf x | x == 0 = error "ulpf of 0"
306 > | True = res (encodeFloat 1 (expf x - floatDigits x))
308 > res 0 = error "ulpf underflow"
315 > floorf :: (RealFloat a) => a -> a
316 > floorf x = fromInteger (floor x)
318 > expf :: (RealFloat a) => a -> Int
319 > expf x = if abs x >= fminN x then exponent x else emin x
321 > truncf :: (RealFloat a) => a -> Int -> a
322 > truncf x n | n <= 0 = error "truncf with n <= 0"
323 > | j >= eemin - p = encodeFloat (i `quot` (r ^ (p - n)))
325 > | True = encodeFloat (i `quot` (r ^ (eemin - j - n)))
328 > (i, j) = decodeFloat x
337 > roundf :: (RealFloat a) => a -> Int -> a
338 > roundf x n | n <= 0 = error "roundf with n <= 0"
339 > | n >= floatDigits x = x
340 > | True = signf x * floorf (abs x / y + 0.5) * y
342 > y = encodeFloat 1 (expf x - n)
348 > fractpart :: (RealFloat a) => a -> a
349 > fractpart x = snd (properFraction x)
353 \section{Recommendations}
356 \begin{thebibliography}{9}
357 \bibitem{hudak} P Hudak, S Peyton Jones, P Wadler et al.
358 {\it Report on the Functional Programming Language Haskell, Version 1.1.}
359 Department of Computing Science, University of Glasgow, August 1991.
360 \bibitem{ieee754} IEEE Standard for Binary Floating-Point Arithmetic.
361 ANSI/IEEE Std 754-1985, 1985.
362 \bibitem{lias} M~Payne, C~Schaffert, and B~A~Wichmann.
363 {\em The Language Compatible Arithmetic Standard}.
364 January 1990. ACM SIGPLAN Notices, Vol 25,
365 pp59-86, and ACM SIGNUM Newsletter, Vol 25, No 1, pp2-43.
366 \end{thebibliography}