Post Scarcity
A prototype for a post scarcity programming environment
Loading...
Searching...
No Matches
ratio.c
Go to the documentation of this file.
1/*
2 * ratio.c
3 *
4 * functions for rational number cells.
5 *
6 * (c) 2017 Simon Brooke <simon@journeyman.cc>
7 * Licensed under GPL version 2.0, or, at your option, any later version.
8 */
9
10#define _GNU_SOURCE
11#include <math.h>
12#include <stdio.h>
13
14#include "arith/integer.h"
15#include "arith/peano.h"
16#include "arith/ratio.h"
17#include "arith/real.h"
18#include "debug.h"
19#include "io/print.h"
20#include "memory/conspage.h"
22#include "memory/stack.h"
23#include "ops/equal.h"
24#include "ops/lispops.h"
25
26
27/**
28 * @brief return, as an int64_t, the greatest common divisor of `m` and `n`,
29 */
30int64_t greatest_common_divisor( int64_t m, int64_t n ) {
31 int o;
32 while ( m ) {
33 o = m;
34 m = n % m;
35 n = o;
36 }
37
38 return o;
39}
40
41/**
42 * @brief return, as an int64_t, the least common multiple of `m` and `n`,
43 */
44int64_t least_common_multiple( int64_t m, int64_t n ) {
45 return m / greatest_common_divisor( m, n ) * n;
46}
47
48struct cons_pointer simplify_ratio( struct cons_pointer pointer ) {
49 struct cons_pointer result = pointer;
50
51 if ( ratiop( pointer ) ) {
52 struct cons_space_object cell = pointer2cell( pointer );
53 struct cons_space_object dividend =
54 pointer2cell( cell.payload.ratio.dividend );
55 struct cons_space_object divisor =
56 pointer2cell( cell.payload.ratio.divisor );
57
58 if ( divisor.payload.integer.value == 1 ) {
59 result = pointer2cell( pointer ).payload.ratio.dividend;
60 } else {
61 int64_t ddrv = dividend.payload.integer.value,
62 drrv = divisor.payload.integer.value,
63 gcd = greatest_common_divisor( ddrv, drrv );
64
65 if ( gcd > 1 ) {
66 if ( drrv / gcd == 1 ) {
67 result =
68 acquire_integer( ( int64_t ) ( ddrv / gcd ), NIL );
69 } else {
71 L"simplify_ratio: %ld/%ld => %ld/%ld\n",
72 ddrv, drrv, ddrv / gcd, drrv / gcd );
73 result =
74 make_ratio( acquire_integer( ddrv / gcd, NIL ),
75 acquire_integer( drrv / gcd, NIL ), false);
76 }
77 }
78 }
79 }
80 // TODO: else throw exception?
81
82 return result;
83
84}
85
86
87/**
88 * return a cons_pointer indicating a number which is the sum of
89 * the ratios indicated by `arg1` and `arg2`.
90 * @exception will return an exception if either `arg1` or `arg2` is not a
91 * rational number.
92 */
94 struct cons_pointer arg2 ) {
95 struct cons_pointer r;
96
97 debug_print( L"\nadd_ratio_ratio: ", DEBUG_ARITH );
99 debug_print( L" + ", DEBUG_ARITH );
101
102 if ( ratiop( arg1 ) && ratiop( arg2 ) ) {
103 struct cons_space_object *cell1 = &pointer2cell( arg1 );
104 struct cons_space_object *cell2 = &pointer2cell( arg2 );
105
106 struct cons_pointer divisor =
107 multiply_integers( cell1->payload.ratio.divisor,
108 cell2->payload.ratio.divisor );
109 struct cons_pointer dividend =
110 add_integers( multiply_integers( cell1->payload.ratio.dividend,
111 cell2->payload.ratio.divisor ),
112 multiply_integers( cell2->payload.ratio.dividend,
113 cell1->payload.ratio.divisor ) );
114 r = make_ratio( dividend, divisor, true );
115 } else {
117 ( L"Shouldn't happen: bad arg to add_ratio_ratio" ),
118 make_cons( arg1,
119 make_cons( arg2, NIL ) ) ),
120 NIL );
121 }
122
123 debug_print( L"add_ratio_ratio => ", DEBUG_ARITH );
125 debug_print( L"\n", DEBUG_ARITH );
126
127 return r;
128}
129
130
131/**
132 * return a cons_pointer indicating a number which is the sum of
133 * the intger indicated by `intarg` and the ratio indicated by
134 * `ratarg`.
135 * @exception if either `intarg` or `ratarg` is not of the expected type.
136 */
138 struct cons_pointer ratarg ) {
139 struct cons_pointer result;
140
141 debug_print( L"\nadd_integer_ratio: ", DEBUG_ARITH );
143 debug_print( L" + ", DEBUG_ARITH );
145
146 if ( integerp( intarg ) && ratiop( ratarg ) ) {
147 struct cons_pointer one = acquire_integer( 1, NIL ),
148 ratio = make_ratio( intarg, one, false );
149
150 result = add_ratio_ratio( ratio, ratarg );
151
152 release_integer( one );
153 dec_ref( ratio );
154 } else {
155 result =
157 ( L"Shouldn't happen: bad arg to add_integer_ratio" ),
158 make_cons( intarg,
159 make_cons( ratarg,
160 NIL ) ) ), NIL );
161 }
162
163 debug_print( L" => ", DEBUG_ARITH );
165 debug_print( L"\n", DEBUG_ARITH );
166
167 return result;
168}
169
170/**
171 * return a cons_pointer to a ratio which represents the value of the ratio
172 * indicated by `arg1` divided by the ratio indicated by `arg2`.
173 * @exception will return an exception if either `arg1` or `arg2` is not a
174 * rational number.
175 */
177 struct cons_pointer arg2 ) {
178 debug_print( L"\ndivide_ratio_ratio: ", DEBUG_ARITH );
180 debug_print( L" / ", DEBUG_ARITH );
182 // TODO: this now has to work if `arg1` is an integer
183 struct cons_pointer i =
184 make_ratio( pointer2cell( arg2 ).payload.ratio.divisor,
185 pointer2cell( arg2 ).payload.ratio.dividend, false ), result =
186 multiply_ratio_ratio( arg1, i );
187
188 dec_ref( i );
189
190 debug_print( L" => ", DEBUG_ARITH );
192 debug_print( L"\n", DEBUG_ARITH );
193
194 return result;
195}
196
197/**
198 * return a cons_pointer indicating a number which is the product of
199 * the ratios indicated by `arg1` and `arg2`.
200 * @exception will return an exception if either `arg1` or `arg2` is not a
201 * rational number.
202 */
204 cons_pointer arg1, struct
205 cons_pointer arg2 ) {
206 // TODO: this now has to work if arg1 is an integer
207 struct cons_pointer result;
208
209 debug_print( L"multiply_ratio_ratio( arg1 = ", DEBUG_ARITH );
211 debug_print( L"; arg2 = ", DEBUG_ARITH );
213 debug_print( L")\n", DEBUG_ARITH );
214
215 if ( ratiop( arg1 ) && ratiop( arg2 ) ) {
216 struct cons_space_object cell1 = pointer2cell( arg1 );
217 struct cons_space_object cell2 = pointer2cell( arg2 );
218 int64_t dd1v =
219 pointer2cell( cell1.payload.ratio.dividend ).payload.integer.value,
220 dd2v =
221 pointer2cell( cell2.payload.ratio.dividend ).payload.integer.value,
222 dr1v =
223 pointer2cell( cell1.payload.ratio.divisor ).payload.integer.value,
224 dr2v =
225 pointer2cell( cell2.payload.ratio.divisor ).payload.integer.value,
226 ddrv = dd1v * dd2v, drrv = dr1v * dr2v;
227
228 struct cons_pointer dividend = acquire_integer( ddrv, NIL );
229 struct cons_pointer divisor = acquire_integer( drrv, NIL );
230 result = make_ratio( dividend, divisor, true );
231
232 release_integer( dividend );
233 release_integer( divisor );
234 } else {
235 result =
237 ( L"Shouldn't happen: bad arg to multiply_ratio_ratio" ),
238 NIL );
239 }
240
241 debug_print( L" => ", DEBUG_ARITH );
243 debug_print( L"\n", DEBUG_ARITH );
244
245 return result;
246}
247
248/**
249 * return a cons_pointer indicating a number which is the product of
250 * the intger indicated by `intarg` and the ratio indicated by
251 * `ratarg`.
252 * @exception if either `intarg` or `ratarg` is not of the expected type.
253 */
255 struct cons_pointer ratarg ) {
256 struct cons_pointer result;
257
258 debug_print( L"\nmultiply_integer_ratio: ", DEBUG_ARITH );
260 debug_print( L" * ", DEBUG_ARITH );
262
263 if ( integerp( intarg ) && ratiop( ratarg ) ) {
264 struct cons_pointer one = acquire_integer( 1, NIL ),
265 ratio = make_ratio( intarg, one, false );
266 result = multiply_ratio_ratio( ratio, ratarg );
267
268 release_integer( one );
269 } else {
270 result =
272 ( L"Shouldn't happen: bad arg to multiply_integer_ratio" ),
273 NIL );
274 }
275
276 debug_print( L" => ", DEBUG_ARITH );
278 debug_print( L"\n", DEBUG_ARITH );
279
280 return result;
281}
282
283
284/**
285 * return a cons_pointer indicating a number which is the difference of
286 * the ratios indicated by `arg1` and `arg2`.
287 * @exception will return an exception if either `arg1` or `arg2` is not a
288 * rational number.
289 */
291 struct cons_pointer arg2 ) {
292 debug_print( L"\nsubtract_ratio_ratio: ", DEBUG_ARITH );
294 debug_print( L" * ", DEBUG_ARITH );
296
297 struct cons_pointer i = negative( arg2 ),
298 result = add_ratio_ratio( arg1, i );
299
300 dec_ref( i );
301
302 return result;
303}
304
305
306/**
307 * Construct a ratio frame from this `dividend` and `divisor`, expected to
308 * be integers, in the context of the stack_frame indicated by this
309 * `frame_pointer`.
310 * @exception if either `dividend` or `divisor` is not an integer.
311 */
312struct cons_pointer make_ratio( struct cons_pointer dividend,
313 struct cons_pointer divisor,
314 bool simplify ) {
315 debug_print( L"make_ratio: dividend = ", DEBUG_ALLOC);
317 debug_print( L"; divisor = ", DEBUG_ALLOC);
319 debug_printf( DEBUG_ALLOC, L"; simplify = %d\n", simplify);
320
321 struct cons_pointer result;
322 if ( integerp( dividend ) && integerp( divisor ) ) {
323 inc_ref( dividend );
324 inc_ref( divisor );
325 struct cons_pointer unsimplified = allocate_cell( RATIOTV );
326 struct cons_space_object *cell = &pointer2cell( unsimplified );
327 cell->payload.ratio.dividend = dividend;
328 cell->payload.ratio.divisor = divisor;
329
330 if ( simplify) {
331 result = simplify_ratio( unsimplified );
332 if ( !eq( result, unsimplified ) ) {
333 dec_ref( unsimplified );
334 }
335 } else {
336 result = unsimplified;
337 }
338 } else {
339 result =
341 ( L"Dividend and divisor of a ratio must be integers" ),
342 NIL );
343 }
344 debug_print( L" => ", DEBUG_ALLOC);
347
348 return result;
349}
350
351/**
352 * True if a and be are identical rationals, else false.
353 *
354 * TODO: we need ways of checking whether rationals are equal
355 * to floats and to integers.
356 */
357bool equal_ratio_ratio( struct cons_pointer a, struct cons_pointer b ) {
358 bool result = false;
359
360 if ( ratiop( a ) && ratiop( b ) ) {
361 struct cons_space_object *cell_a = &pointer2cell( a );
362 struct cons_space_object *cell_b = &pointer2cell( b );
363
364 result = equal_integer_integer( cell_a->payload.ratio.dividend,
365 cell_b->payload.ratio.dividend ) &&
366 equal_integer_integer( cell_a->payload.ratio.divisor,
367 cell_b->payload.ratio.divisor );
368 }
369
370 return result;
371}
372
373/**
374 * @brief convert a ratio to an equivalent long double.
375 *
376 * @param rat a pointer to a ratio.
377 * @return long double
378 */
379long double c_ratio_to_ld( struct cons_pointer rat ) {
380 long double result = NAN;
381
382 debug_print( L"\nc_ratio_to_ld: ", DEBUG_ARITH );
384
385 if ( ratiop( rat ) ) {
386 struct cons_space_object *cell_a = &pointer2cell( rat );
387 struct cons_pointer dv = cell_a->payload.ratio.divisor;
388 struct cons_space_object *dv_cell = &pointer2cell( dv );
389 struct cons_pointer dd = cell_a->payload.ratio.dividend;
390 struct cons_space_object *dd_cell = &pointer2cell( dd );
391
392 if ( nilp( dv_cell->payload.integer.more )
393 && nilp( dd_cell->payload.integer.more ) ) {
394 result =
395 ( ( long double ) dd_cell->payload.integer.value ) /
396 ( ( long double ) dv_cell->payload.integer.value );;
397 } else {
398 fwprintf( stderr,
399 L"real conversion is not yet implemented for bignums rationals." );
400 }
401 }
402
403 debug_printf( DEBUG_ARITH, L"\nc_ratio_to_ld returning %d\n", result );
404
405 return result;
406}
struct cons_pointer allocate_cell(uint32_t tag)
Allocates a cell with the specified tag.
Definition conspage.c:222
#define ratiop(conspoint)
true if conspoint points to a rational number cell, else false
union cons_space_object::@3 payload
#define NIL
a cons pointer which points to the special NIL cell
#define RATIOTV
The string RTIO, considered as an unsigned int.
#define nilp(conspoint)
true if conspoint points to the special cell NIL, else false (there should only be one of these so it...
struct cons_pointer c_string_to_lisp_string(wchar_t *string)
Return a lisp string representation of this wide character string.
struct cons_pointer inc_ref(struct cons_pointer pointer)
increment the reference count of the object at this cons pointer.
struct cons_pointer dec_ref(struct cons_pointer pointer)
Decrement the reference count of the object at this cons pointer.
#define pointer2cell(pointer)
given a cons_pointer as argument, return the cell.
#define integerp(conspoint)
true if conspoint points to an integer cell, else false
struct cons_pointer make_cons(struct cons_pointer car, struct cons_pointer cdr)
Construct a cons cell from this pair of pointers.
An indirect pointer to a cons cell.
an object in cons space.
void debug_println(int level)
print a line feed to stderr, if verbosity matches level.
Definition debug.c:85
void debug_printf(int level, wchar_t *format,...)
wprintf adapted for the debug logging system.
Definition debug.c:101
void debug_print(wchar_t *message, int level)
print this debug message to stderr, if verbosity matches level.
Definition debug.c:41
void debug_print_object(struct cons_pointer pointer, int level)
print the object indicated by this pointer to stderr, if verbosity matches level.
Definition debug.c:119
#define DEBUG_ARITH
Print messages debugging arithmetic operations.
Definition debug.h:28
#define DEBUG_ALLOC
Print messages debugging memory allocation.
Definition debug.h:21
bool eq(struct cons_pointer a, struct cons_pointer b)
Shallow, and thus cheap, equality: true if these two objects are the same object, else false.
Definition equal.c:24
bool equal_integer_integer(struct cons_pointer a, struct cons_pointer b)
true if a and be are both integers whose value is the same value.
Definition integer.c:511
struct cons_pointer multiply_integers(struct cons_pointer a, struct cons_pointer b)
Return a pointer to an integer representing the product of the integers pointed to by a and b.
Definition integer.c:343
void release_integer(struct cons_pointer p)
if the value of p is less than the size of the small integer cache (and thus it was presumably suppli...
Definition integer.c:163
struct cons_pointer add_integers(struct cons_pointer a, struct cons_pointer b)
Return a pointer to an integer representing the sum of the integers pointed to by a and b.
Definition integer.c:224
struct cons_pointer acquire_integer(int64_t value, struct cons_pointer more)
Supply small valued integers from the small integer cache, if available.
Definition integer.c:129
struct cons_pointer throw_exception(struct cons_pointer message, struct cons_pointer frame_pointer)
Throw an exception.
Definition lispops.c:1208
struct cons_pointer negative(struct cons_pointer arg)
return a cons_pointer indicating a number which is the 0 - the number indicated by arg.
Definition peano.c:489
long double c_ratio_to_ld(struct cons_pointer rat)
convert a ratio to an equivalent long double.
Definition ratio.c:379
int64_t greatest_common_divisor(int64_t m, int64_t n)
return, as an int64_t, the greatest common divisor of m and n,
Definition ratio.c:30
struct cons_pointer add_ratio_ratio(struct cons_pointer arg1, struct cons_pointer arg2)
return a cons_pointer indicating a number which is the sum of the ratios indicated by arg1 and arg2.
Definition ratio.c:93
struct cons_pointer multiply_ratio_ratio(struct cons_pointer arg1, struct cons_pointer arg2)
return a cons_pointer indicating a number which is the product of the ratios indicated by arg1 and ar...
Definition ratio.c:203
bool equal_ratio_ratio(struct cons_pointer a, struct cons_pointer b)
True if a and be are identical rationals, else false.
Definition ratio.c:357
struct cons_pointer divide_ratio_ratio(struct cons_pointer arg1, struct cons_pointer arg2)
return a cons_pointer to a ratio which represents the value of the ratio indicated by arg1 divided by...
Definition ratio.c:176
int64_t least_common_multiple(int64_t m, int64_t n)
return, as an int64_t, the least common multiple of m and n,
Definition ratio.c:44
struct cons_pointer multiply_integer_ratio(struct cons_pointer intarg, struct cons_pointer ratarg)
return a cons_pointer indicating a number which is the product of the intger indicated by intarg and ...
Definition ratio.c:254
struct cons_pointer add_integer_ratio(struct cons_pointer intarg, struct cons_pointer ratarg)
return a cons_pointer indicating a number which is the sum of the intger indicated by intarg and the ...
Definition ratio.c:137
struct cons_pointer subtract_ratio_ratio(struct cons_pointer arg1, struct cons_pointer arg2)
return a cons_pointer indicating a number which is the difference of the ratios indicated by arg1 and...
Definition ratio.c:290
struct cons_pointer make_ratio(struct cons_pointer dividend, struct cons_pointer divisor, bool simplify)
Construct a ratio frame from this dividend and divisor, expected to be integers, in the context of th...
Definition ratio.c:312
struct cons_pointer simplify_ratio(struct cons_pointer pointer)
ratio.h
Definition ratio.c:48