Files
mercury/samples/e.m
Julien Fischer 14639c8b03 Fix omissions in the char module.
The functions det_int_to_{binary,octal,decimal,hex)_digit/1 were supposed to
have been added at the same time as the corresponding semidet predicates but
weren't: add them.

In the char module, don't call unexpected/3 in cases where the error arises as
a result of bad inputs: throwing an exception in that case *is* expected.

library/char.m:
     As above.

NEWS:
     Announce the above additions.

samples/e.m:
     Avoid a call to an obsolete predicate and update syntax.
2015-08-30 14:49:22 +10:00

150 lines
4.3 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
%
% File: e.m.
% Main author: bromage.
%
% This source file is hereby placed in the public domain. -bromage.
%
% Calculate the base of natural logarithms using lazy evaluation.
%
% The algorithm is O(N^2) in the number of digits requested.
%
%-----------------------------------------------------------------------------%
:- module e.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module char.
:- import_module int.
:- import_module list.
:- import_module require.
:- import_module string.
%-----------------------------------------------------------------------------%
% Default number of digits displayed (if this is not specified
% on the command line).
%
:- func default_digits = int.
default_digits = 1000.
% Change this for a base other than 10. Any integer between
% 2 and 36 makes sense.
%
:- func base = int.
base = 10.
% Number of columns on the terminal.
%
:- func columns = int.
columns = 78.
%-----------------------------------------------------------------------------%
% This is a simple implementation of an infinite lazy stream.
%
:- type int_stream
---> [int | int_stream]
; closure((func) = int_stream).
:- inst int_stream ==
bound([ground | int_stream] ; closure((func) = is_out is det)).
:- mode is_in == in(int_stream).
:- mode is_out == out(int_stream).
%-----------------------------------------------------------------------------%
% An infinite stream of ones.
%
:- func ones = (int_stream :: is_out) is det.
ones = [1 | closure((func) = ones)].
% All the digits of e in one stream.
%
:- func digits_of_e = (int_stream :: is_out) is det.
digits_of_e = next_digit(ones).
:- func next_digit(int_stream::is_in) = (int_stream::is_out) is det.
next_digit(Stream0) = [Digit | closure((func) = next_digit(Stream))] :-
scale(2, Digit, Stream0, Stream).
:- pred scale(int::in, int::out, int_stream::is_in, int_stream::is_out) is det.
scale(C, Digit, closure(Func), Stream) :-
scale(C, Digit, apply(Func), Stream).
scale(C, Digit, [D | Ds], Stream) :-
K = base * D,
KdC = K // C,
( if KdC = (K + base - 1) // C then
% We have the next digit. Construct a closure to
% generate the rest.
Digit = KdC,
Stream = closure((func) = [K rem C + NextDigit | Stream0] :-
scale(C + 1, NextDigit, Ds, Stream0)
)
else
% We have a carry to factor in, so calculate the next
% digit eagerly then add it on.
scale(C + 1, A1, Ds, B1),
Digit = (K + A1) // C,
Stream = [(K + A1) rem C | B1]
).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
main(!IO) :-
io.command_line_arguments(Args, !IO),
( if
Args = [Arg | _],
string.to_int(Arg, Digits0)
then
Digits = Digits0
else
Digits = default_digits
),
string.int_to_base_string(2, base, BaseString),
io.write_strings([BaseString, "."], !IO),
string.length(BaseString, BaseStringLength),
main_2(Digits, columns - BaseStringLength - 1, digits_of_e, !IO),
io.nl(!IO).
% Print out digits until we don't have any more.
%
:- pred main_2(int::in, int::in, int_stream::is_in, io::di, io::uo) is det.
main_2(Digits, Columns, closure(Func), !IO) :-
main_2(Digits, Columns, apply(Func), !IO).
main_2(Digits, Columns, [I | Is], !IO) :-
( if Digits = 0 then
true
else if Columns = 0 then
io.nl(!IO),
main_2(Digits, columns, [I | Is], !IO)
else
Digit = char.det_int_to_decimal_digit(I),
io.write_char(Digit, !IO),
main_2(Digits - 1, Columns - 1, Is, !IO)
).
%-----------------------------------------------------------------------------%
:- end_module e.
%-----------------------------------------------------------------------------%