mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 09:23:44 +00:00
extras/gator/gator:
Update programming style. Fix indentation. Add a vim modeline.
extras/gator/genotype.m:
extras/gator/phenotype.m:
Fix indentation.
extras/lex/regex.m:
Replace if-then-else chain with a switch.
extras/base64/base64.m:
extras/cgi/cgi.m:
extras/cgi/form_test.m:
extras/cgi/html.m:
extras/cgi/mercury_www.m:
extras/complex_numbers/complex_numbers.complex.m:
extras/complex_numbers/complex_numbers.complex_float.m:
extras/complex_numbers/complex_numbers.complex_imag.m:
extras/complex_numbers/complex_numbers.float_complex.m:
extras/complex_numbers/complex_numbers.float_imag.m:
extras/complex_numbers/complex_numbers.imag.m:
extras/complex_numbers/complex_numbers.imag_complex.m:
extras/complex_numbers/complex_numbers.imag_float.m:
extras/complex_numbers/complex_numbers.m:
extras/curs/curs.m:
extras/dynamic_linking/dl_test.m:
extras/dynamic_linking/dl_test2.m:
extras/dynamic_linking/hello.m:
extras/error/error.m:
extras/fixed/fixed.m:
extras/fixed/mercury_fixed.m:
extras/java_extras/make_temp.m:
extras/lex/lex.automata.m:
extras/lex/lex.buf.m:
extras/lex/lex.convert_NFA_to_DFA.m:
extras/lex/lex.lexeme.m:
extras/lex/lex.m:
extras/lex/lex.regexp.m:
extras/logged_output/logged_output.m:
extras/logged_output/main.m:
extras/monte/doit.m:
extras/monte/dots.m:
extras/monte/geom.m:
extras/monte/hg.m:
extras/monte/monte.m:
extras/monte/rnd.m:
extras/mopenssl/mopenssl.m:
extras/odbc/mercury_odbc.m:
extras/odbc/odbc.m:
extras/odbc/odbc_test.m:
extras/posix/posix.chdir.m:
extras/posix/posix.closedir.m:
extras/posix/posix.dup.m:
extras/posix/posix.exec.m:
extras/posix/posix.fork.m:
extras/posix/posix.getpid.m:
extras/posix/posix.kill.m:
extras/posix/posix.lseek.m:
extras/posix/posix.m:
extras/posix/posix.mkdir.m:
extras/posix/posix.open.m:
extras/posix/posix.opendir.m:
extras/posix/posix.pipe.m:
extras/posix/posix.read.m:
extras/posix/posix.readdir.m:
extras/posix/posix.realpath.m:
extras/posix/posix.rmdir.m:
extras/posix/posix.select.m:
extras/posix/posix.sleep.m:
extras/posix/posix.socket.m:
extras/posix/posix.stat.m:
extras/posix/posix.strerror.m:
extras/posix/posix.wait.m:
extras/posix/posix.write.m:
extras/quickcheck/qcheck.m:
extras/quickcheck/rnd.m:
extras/quickcheck/test_qcheck.m:
extras/show_ops/show_ops.m:
extras/split_file/split_file.m:
extras/windows_installer_generator/wix.m:
extras/windows_installer_generator/wix_files.m:
extras/windows_installer_generator/wix_gui.m:
extras/windows_installer_generator/wix_installer.m:
extras/windows_installer_generator/wix_util.m:
Apply tools/stdlines to all these files.
442 lines
12 KiB
Mathematica
442 lines
12 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2006, 2011 The University of Melbourne.
|
|
% Copyright (C) 2015, 2018, 2025 The Mercury team.
|
|
% This file is distributed under the terms specified in COPYING.LIB.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: fixed.m
|
|
% Author: Peter Ross <pro@missioncriticalit.com>
|
|
%
|
|
% Implementation of fixed point arithmetic which is equivalent to cobol
|
|
% fixed point arithmetic.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module fixed.
|
|
:- interface.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Represents a fixed point number at some given precision.
|
|
%
|
|
:- type fixed.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func - fixed = fixed.
|
|
:- func fixed + fixed = fixed.
|
|
:- func fixed - fixed = fixed.
|
|
:- func fixed * fixed = fixed.
|
|
|
|
% div(MinP, A, B) is A / B where the result has
|
|
% to have at least a precision MinP.
|
|
%
|
|
:- func div(int, fixed, fixed) = fixed.
|
|
|
|
% Increase or decrease the precision of the given fixed.
|
|
% We decrease the precision by truncating the result.
|
|
%
|
|
:- func precision(int, fixed) = fixed.
|
|
|
|
% Return the integer part of the fixed point number.
|
|
%
|
|
:- func to_int(fixed) = int.
|
|
|
|
% Given a fixed return the floating point number
|
|
% which represents that fixed point number.
|
|
%
|
|
:- func to_float(fixed) = float.
|
|
|
|
% truncate(P, F) truncates the number, F, to precision, P.
|
|
%
|
|
:- func truncate(int, fixed) = fixed.
|
|
|
|
% round(P, F) rounds the number, F, to precision, P.
|
|
%
|
|
:- func round(int, fixed) = fixed.
|
|
|
|
% Is the given floating point number equal to zero?
|
|
%
|
|
:- pred is_zero(fixed::in) is semidet.
|
|
|
|
% Determine the precision with which the given number
|
|
% is stored.
|
|
%
|
|
:- func fixed_precision(fixed) = int.
|
|
|
|
% Compare two fixed point numbers.
|
|
%
|
|
:- func compare_fixed(fixed::in, fixed::in) = (comparison_result::uo) is det.
|
|
|
|
% Get the fractional part of a fixed point number as a string.
|
|
%
|
|
:- func get_fraction_part_string(fixed) = string.
|
|
|
|
% Get the integral part of a fixed point number as % a string.
|
|
%
|
|
:- func get_whole_part_string(fixed) = string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Comparison operators for fixed point numbers.
|
|
%
|
|
|
|
:- pred (fixed::in) == (fixed::in) is semidet.
|
|
:- pred (fixed::in) \== (fixed::in) is semidet.
|
|
|
|
:- pred (fixed::in) < (fixed::in) is semidet.
|
|
:- pred (fixed::in) > (fixed::in) is semidet.
|
|
:- pred (fixed::in) =< (fixed::in) is semidet.
|
|
:- pred (fixed::in) >= (fixed::in) is semidet.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- typeclass fixed(T) where [
|
|
% Return the fixed point representation of T, with the supplied precision.
|
|
func to_fixed(int, T) = fixed
|
|
].
|
|
|
|
:- instance fixed(int).
|
|
|
|
% The float is rounded.
|
|
:- instance fixed(float).
|
|
|
|
% The string is truncated.
|
|
:- instance fixed(string).
|
|
|
|
% Output a fixed point number as a string.
|
|
%
|
|
:- func to_string(fixed) = string.
|
|
|
|
% Given a string, return the fixed which represents that string.
|
|
%
|
|
:- func to_fixed(string) = fixed.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module char.
|
|
:- import_module float.
|
|
:- import_module int.
|
|
:- import_module integer.
|
|
:- import_module list.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type fixed
|
|
---> fixed(
|
|
precision :: int,
|
|
number :: integer
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
- fixed(P, N) = fixed(P, integer(-1) * N).
|
|
|
|
X + Y = fixed(P, A + B) :-
|
|
compare(Result, X ^ precision, Y ^ precision),
|
|
(
|
|
Result = (<),
|
|
P = Y ^ precision,
|
|
A = precision(P, X) ^ number,
|
|
B = Y ^ number
|
|
;
|
|
Result = (=),
|
|
P = X ^ precision,
|
|
A = X ^ number,
|
|
B = Y ^ number
|
|
;
|
|
Result = (>),
|
|
P = X ^ precision,
|
|
A = X ^ number,
|
|
B = precision(P, Y) ^ number
|
|
).
|
|
|
|
X - Y = fixed(P, A - B) :-
|
|
compare(Result, X ^ precision, Y ^ precision),
|
|
(
|
|
Result = (<),
|
|
P = Y ^ precision,
|
|
A = precision(P, X) ^ number,
|
|
B = Y ^ number
|
|
;
|
|
Result = (=),
|
|
P = X ^ precision,
|
|
A = X ^ number,
|
|
B = Y ^ number
|
|
;
|
|
Result = (>),
|
|
P = X ^ precision,
|
|
A = X ^ number,
|
|
B = precision(P, Y) ^ number
|
|
).
|
|
|
|
X * Y = fixed(X ^ precision + Y ^ precision, X ^ number * Y ^ number).
|
|
|
|
div(MinP, X, Y) = fixed(P, N) :-
|
|
Diff = X ^ precision - Y ^ precision,
|
|
( if Diff < MinP then
|
|
P = MinP,
|
|
N = (X ^ number * scale(MinP - Diff)) // Y ^ number
|
|
else
|
|
P = Diff,
|
|
N = X ^ number // Y ^ number
|
|
).
|
|
|
|
precision(DesiredP, fixed(ActualP, N0)) = fixed(DesiredP, N) :-
|
|
compare(Result, DesiredP, ActualP),
|
|
(
|
|
Result = (<),
|
|
N = N0 // scale(ActualP - DesiredP)
|
|
;
|
|
Result = (=),
|
|
N = N0
|
|
;
|
|
Result = (>),
|
|
N = N0 * scale(DesiredP - ActualP)
|
|
).
|
|
|
|
:- func scale(int) = integer.
|
|
|
|
scale(X) = integer(10) `pow` integer(X).
|
|
|
|
truncate(DesiredP, F) = precision(DesiredP, F).
|
|
|
|
round(DesiredP, fixed(ActualP, N0)) = fixed(DesiredP, N) :-
|
|
compare(Result, DesiredP, ActualP),
|
|
(
|
|
Result = (<),
|
|
Scale = scale(ActualP - DesiredP),
|
|
Rem = N0 rem Scale,
|
|
( if Rem << 1 >= Scale then
|
|
N = N0 // Scale + integer.one
|
|
else
|
|
N = N0 // Scale
|
|
)
|
|
;
|
|
Result = (=),
|
|
N = N0
|
|
;
|
|
Result = (>),
|
|
N = N0 * scale(DesiredP - ActualP)
|
|
).
|
|
|
|
is_zero(N) :-
|
|
integer.is_zero(N ^ number).
|
|
|
|
fixed_precision(N) = N ^ precision.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
X == Y :-
|
|
Result = compare_fixed(X, Y),
|
|
Result = (=).
|
|
|
|
X \== Y :-
|
|
Result = compare_fixed(X, Y),
|
|
( Result = (>)
|
|
; Result = (<)
|
|
).
|
|
|
|
X < Y :-
|
|
Result = compare_fixed(X, Y),
|
|
Result = (<).
|
|
|
|
X > Y :-
|
|
Result = compare_fixed(X, Y),
|
|
Result = (>).
|
|
|
|
X =< Y :-
|
|
Result = compare_fixed(X, Y),
|
|
( Result = (<)
|
|
; Result = (=)
|
|
).
|
|
|
|
X >= Y :-
|
|
Result = compare_fixed(X, Y),
|
|
( Result = (>)
|
|
; Result = (=)
|
|
).
|
|
|
|
compare_fixed(X, Y) = Result :-
|
|
Z = (X - Y) ^ number,
|
|
( if Z < integer.zero then
|
|
Result = (<)
|
|
else if Z = integer.zero then
|
|
Result = (=)
|
|
else
|
|
Result = (>)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- instance fixed(int) where [
|
|
to_fixed(N, I) = fixed(N, integer(I) * (integer(10) `pow` integer(N)))
|
|
].
|
|
|
|
:- instance fixed(float) where [
|
|
to_fixed(N, F) = to_fixed(N, string.format(Spec, [f(F)])) :-
|
|
Spec = string.format("%%.%df", [i(N)])
|
|
].
|
|
|
|
:- instance fixed(string) where [
|
|
to_fixed(N, S) = fixed(N, scaled_integer(N, S))
|
|
].
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_string(fixed(N, Int)) = Str :-
|
|
( if N = 0 then
|
|
Str = integer.to_string(Int)
|
|
else
|
|
Cs0 = to_char_list(integer.to_string(Int)),
|
|
insert_decimal_point(N, Cs0, P, Cs1),
|
|
( if N >= P then
|
|
Cs = ['0', '.'] ++ list.duplicate(N - P, '0') ++ Cs1
|
|
else
|
|
Cs = Cs1
|
|
),
|
|
Str = from_char_list(Cs)
|
|
).
|
|
|
|
:- pred insert_decimal_point(int::in, list(char)::in,
|
|
int::out, list(char)::out) is det.
|
|
|
|
insert_decimal_point(_, [], 0, []).
|
|
insert_decimal_point(N, [C | Cs], P + 1, L) :-
|
|
insert_decimal_point(N, Cs, P, L0),
|
|
( if N = P then
|
|
L = [C, '.' | L0]
|
|
else
|
|
L = [C | L0]
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
to_int(F) = det_to_int(I) :-
|
|
fixed(_, I) = precision(0, F).
|
|
|
|
to_float(fixed(P, N)) = float(N) / pow(10.0, P).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Deterministic version of scaled_integer which throws an error, instead
|
|
% of failing.
|
|
%
|
|
:- func scaled_integer(int, string) = integer.
|
|
|
|
scaled_integer(N, Str) =
|
|
( if scaled_integer(N, Str, ScaledInteger) then
|
|
ScaledInteger
|
|
else
|
|
func_error("scaled_integer: " ++ Str)
|
|
).
|
|
|
|
% scaled_integer(N, S, SI) is true iff
|
|
% SI is a scaled integer which represents the string, S, as a fixed
|
|
% point number of order N.
|
|
%
|
|
% Fails if S doesn't represent a number.
|
|
%
|
|
% Note that SI is a truncated version of S, if S has greater precision
|
|
% than N. eg fixed(1, "1.36", integer(13)) is true, there is no rounding.
|
|
%
|
|
:- pred scaled_integer(int::in, string::in, integer::out) is semidet.
|
|
|
|
scaled_integer(N, Str, ScaledInteger) :-
|
|
Str \= "",
|
|
L = to_char_list(Str),
|
|
( if L = ['-' | Cs] then
|
|
scaled_integer(N, Cs, integer(0), ScaledInteger0),
|
|
ScaledInteger = integer(-1) * ScaledInteger0
|
|
else if L = ['+' | Cs] then
|
|
scaled_integer(N, Cs, integer(0), ScaledInteger)
|
|
else
|
|
scaled_integer(N, L, integer(0), ScaledInteger)
|
|
).
|
|
|
|
|
|
:- pred scaled_integer(int::in, list(char)::in,
|
|
integer::in, integer::out) is semidet.
|
|
|
|
scaled_integer(N, [], A0, A) :-
|
|
A = A0 * scale(N).
|
|
scaled_integer(N, [C|Cs], A0, A) :-
|
|
( if C = ('.') then
|
|
L = list.take_upto(N, Cs),
|
|
fraction(L, A0, A1),
|
|
A = A1 * (integer(10) `pow` integer(N - length(L)))
|
|
else
|
|
decimal_digit_to_int(C, I),
|
|
scaled_integer(N, Cs, A0 * integer(10) + integer(I), A)
|
|
).
|
|
|
|
:- pred fraction(list(char)::in, integer::in, integer::out) is semidet.
|
|
|
|
fraction([], A, A).
|
|
fraction([C | Cs], A0, A) :-
|
|
decimal_digit_to_int(C, I),
|
|
fraction(Cs, A0 * integer(10) + integer(I), A).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- import_module maybe.
|
|
|
|
to_fixed(Str) = Fixed :-
|
|
L = to_char_list(Str),
|
|
( if L = ['-' | Cs] then
|
|
Factor = integer(-1),
|
|
List = Cs
|
|
else if L = ['+' | Cs] then
|
|
Factor = integer(+1),
|
|
List = Cs
|
|
else if L = [_ | _] then
|
|
Factor = integer(+1),
|
|
List = L
|
|
else
|
|
error("to_fixed: empty string")
|
|
),
|
|
( if parse_fixed(List, integer(0), N0, no, P) then
|
|
N = Factor * N0,
|
|
Fixed = fixed(P, N)
|
|
else
|
|
error("to_fixed: " ++ Str)
|
|
).
|
|
|
|
:- pred parse_fixed(list(char)::in, integer::in, integer::out,
|
|
maybe(int)::in, int::out) is semidet.
|
|
|
|
parse_fixed([], I, I, no, 0).
|
|
parse_fixed([], I, I, yes(P), P).
|
|
parse_fixed([C | Cs], I0, I, no, P) :-
|
|
( if C = ('.') then
|
|
parse_fixed(Cs, I0, I, yes(0), P)
|
|
else
|
|
decimal_digit_to_int(C, CInt),
|
|
parse_fixed(Cs, integer(10) * I0 + integer(CInt), I, no, P)
|
|
).
|
|
parse_fixed([C | Cs], I0, I, yes(P0), P) :-
|
|
decimal_digit_to_int(C, CInt),
|
|
parse_fixed(Cs, integer(10) * I0 + integer(CInt), I, yes(P0 + 1), P).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
get_fraction_part_string(fixed(Precision, N)) = FracStr :-
|
|
FracPart = N mod pow(integer(10), integer(Precision)),
|
|
FracStr = to_string(FracPart).
|
|
|
|
get_whole_part_string(fixed(Precision, N)) = WholeStr :-
|
|
WholePart = N div pow(integer(10), integer(Precision)),
|
|
WholeStr = to_string(WholePart).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module fixed.
|
|
%---------------------------------------------------------------------------%
|