Post Scarcity 0.0.6
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 ),
76 false );
77 }
78 }
79 }
80 }
81 // TODO: else throw exception?
82
83 return result;
84
85}
86
87
88/**
89 * return a cons_pointer indicating a number which is the sum of
90 * the ratios indicated by `arg1` and `arg2`.
91 * @exception will return an exception if either `arg1` or `arg2` is not a
92 * rational number.
93 */
95 struct cons_pointer arg2 ) {
96 struct cons_pointer r;
97
98 debug_print( L"\nadd_ratio_ratio: ", DEBUG_ARITH );
100 debug_print( L" + ", DEBUG_ARITH );
102
103 if ( ratiop( arg1 ) && ratiop( arg2 ) ) {
104 struct cons_space_object *cell1 = &pointer2cell( arg1 );
105 struct cons_space_object *cell2 = &pointer2cell( arg2 );
106
107 struct cons_pointer divisor =
108 multiply_integers( cell1->payload.ratio.divisor,
109 cell2->payload.ratio.divisor );
110 struct cons_pointer dividend =
111 add_integers( multiply_integers( cell1->payload.ratio.dividend,
112 cell2->payload.ratio.divisor ),
113 multiply_integers( cell2->payload.ratio.dividend,
114 cell1->payload.ratio.divisor ) );
115 r = make_ratio( dividend, divisor, true );
116 } else {
119 ( L"Shouldn't happen: bad arg to add_ratio_ratio" ),
120 make_cons( arg1,
121 make_cons( arg2, NIL ) ) ),
122 NIL );
123 }
124
125 debug_print( L"add_ratio_ratio => ", DEBUG_ARITH );
127 debug_print( L"\n", DEBUG_ARITH );
128
129 return r;
130}
131
132
133/**
134 * return a cons_pointer indicating a number which is the sum of
135 * the intger indicated by `intarg` and the ratio indicated by
136 * `ratarg`.
137 * @exception if either `intarg` or `ratarg` is not of the expected type.
138 */
140 struct cons_pointer ratarg ) {
141 struct cons_pointer result;
142
143 debug_print( L"\nadd_integer_ratio: ", DEBUG_ARITH );
145 debug_print( L" + ", DEBUG_ARITH );
147
148 if ( integerp( intarg ) && ratiop( ratarg ) ) {
149 struct cons_pointer one = acquire_integer( 1, NIL ),
150 ratio = make_ratio( intarg, one, false );
151
152 result = add_ratio_ratio( ratio, ratarg );
153
154 release_integer( one );
155 dec_ref( ratio );
156 } else {
157 result =
160 ( L"Shouldn't happen: bad arg to add_integer_ratio" ),
161 make_cons( intarg,
162 make_cons( ratarg,
163 NIL ) ) ), NIL );
164 }
165
166 debug_print( L" => ", DEBUG_ARITH );
168 debug_print( L"\n", DEBUG_ARITH );
169
170 return result;
171}
172
173/**
174 * return a cons_pointer to a ratio which represents the value of the ratio
175 * indicated by `arg1` divided by the ratio indicated by `arg2`.
176 * @exception will return an exception if either `arg1` or `arg2` is not a
177 * rational number.
178 */
180 struct cons_pointer arg2 ) {
181 debug_print( L"\ndivide_ratio_ratio: ", DEBUG_ARITH );
183 debug_print( L" / ", DEBUG_ARITH );
185 // TODO: this now has to work if `arg1` is an integer
186 struct cons_pointer i =
187 make_ratio( pointer2cell( arg2 ).payload.ratio.divisor,
188 pointer2cell( arg2 ).payload.ratio.dividend, false ),
189 result = multiply_ratio_ratio( arg1, i );
190
191 dec_ref( i );
192
193 debug_print( L" => ", DEBUG_ARITH );
195 debug_print( L"\n", DEBUG_ARITH );
196
197 return result;
198}
199
200/**
201 * return a cons_pointer indicating a number which is the product of
202 * the ratios indicated by `arg1` and `arg2`.
203 * @exception will return an exception if either `arg1` or `arg2` is not a
204 * rational number.
205 */
207 cons_pointer arg1, struct
208 cons_pointer arg2 ) {
209 // TODO: this now has to work if arg1 is an integer
210 struct cons_pointer result;
211
212 debug_print( L"multiply_ratio_ratio( arg1 = ", DEBUG_ARITH );
214 debug_print( L"; arg2 = ", DEBUG_ARITH );
216 debug_print( L")\n", DEBUG_ARITH );
217
218 if ( ratiop( arg1 ) && ratiop( arg2 ) ) {
219 struct cons_space_object cell1 = pointer2cell( arg1 );
220 struct cons_space_object cell2 = pointer2cell( arg2 );
221 int64_t dd1v =
222 pointer2cell( cell1.payload.ratio.dividend ).payload.integer.value,
223 dd2v =
224 pointer2cell( cell2.payload.ratio.dividend ).payload.integer.value,
225 dr1v =
226 pointer2cell( cell1.payload.ratio.divisor ).payload.integer.value,
227 dr2v =
228 pointer2cell( cell2.payload.ratio.divisor ).payload.integer.value,
229 ddrv = dd1v * dd2v, drrv = dr1v * dr2v;
230
231 struct cons_pointer dividend = acquire_integer( ddrv, NIL );
232 struct cons_pointer divisor = acquire_integer( drrv, NIL );
233 result = make_ratio( dividend, divisor, true );
234
235 release_integer( dividend );
236 release_integer( divisor );
237 } else {
238 result =
241 ( L"Shouldn't happen: bad arg to multiply_ratio_ratio" ),
242 NIL );
243 }
244
245 debug_print( L" => ", DEBUG_ARITH );
247 debug_print( L"\n", DEBUG_ARITH );
248
249 return result;
250}
251
252/**
253 * return a cons_pointer indicating a number which is the product of
254 * the intger indicated by `intarg` and the ratio indicated by
255 * `ratarg`.
256 * @exception if either `intarg` or `ratarg` is not of the expected type.
257 */
259 struct cons_pointer ratarg ) {
260 struct cons_pointer result;
261
262 debug_print( L"\nmultiply_integer_ratio: ", DEBUG_ARITH );
264 debug_print( L" * ", DEBUG_ARITH );
266
267 if ( integerp( intarg ) && ratiop( ratarg ) ) {
268 struct cons_pointer one = acquire_integer( 1, NIL ),
269 ratio = make_ratio( intarg, one, false );
270 result = multiply_ratio_ratio( ratio, ratarg );
271
272 release_integer( one );
273 } else {
274 result =
277 ( L"Shouldn't happen: bad arg to multiply_integer_ratio" ),
278 NIL );
279 }
280
281 debug_print( L" => ", DEBUG_ARITH );
283 debug_print( L"\n", DEBUG_ARITH );
284
285 return result;
286}
287
288
289/**
290 * return a cons_pointer indicating a number which is the difference of
291 * the ratios indicated by `arg1` and `arg2`.
292 * @exception will return an exception if either `arg1` or `arg2` is not a
293 * rational number.
294 */
296 struct cons_pointer arg2 ) {
297 debug_print( L"\nsubtract_ratio_ratio: ", DEBUG_ARITH );
299 debug_print( L" * ", DEBUG_ARITH );
301
302 struct cons_pointer i = negative( arg2 ),
303 result = add_ratio_ratio( arg1, i );
304
305 dec_ref( i );
306
307 return result;
308}
309
310
311/**
312 * Construct a ratio frame from this `dividend` and `divisor`, expected to
313 * be integers, in the context of the stack_frame indicated by this
314 * `frame_pointer`.
315 * @exception if either `dividend` or `divisor` is not an integer.
316 */
317struct cons_pointer make_ratio( struct cons_pointer dividend,
318 struct cons_pointer divisor, bool simplify ) {
319 debug_print( L"make_ratio: dividend = ", DEBUG_ALLOC );
320 debug_print_object( dividend, DEBUG_ALLOC );
321 debug_print( L"; divisor = ", DEBUG_ALLOC );
323 debug_printf( DEBUG_ALLOC, L"; simplify = %d\n", simplify );
324
325 struct cons_pointer result;
326 if ( integerp( dividend ) && integerp( divisor ) ) {
327 inc_ref( dividend );
328 inc_ref( divisor );
329 struct cons_pointer unsimplified = allocate_cell( RATIOTV );
330 struct cons_space_object *cell = &pointer2cell( unsimplified );
331 cell->payload.ratio.dividend = dividend;
332 cell->payload.ratio.divisor = divisor;
333
334 if ( simplify ) {
335 result = simplify_ratio( unsimplified );
336 if ( !eq( result, unsimplified ) ) {
337 dec_ref( unsimplified );
338 }
339 } else {
340 result = unsimplified;
341 }
342 } else {
343 result =
346 ( L"Dividend and divisor of a ratio must be integers" ),
347 NIL );
348 }
349 debug_print( L" => ", DEBUG_ALLOC );
352
353 return result;
354}
355
356/**
357 * True if a and be are identical rationals, else false.
358 *
359 * TODO: we need ways of checking whether rationals are equal
360 * to floats and to integers.
361 */
362bool equal_ratio_ratio( struct cons_pointer a, struct cons_pointer b ) {
363 bool result = false;
364
365 if ( ratiop( a ) && ratiop( b ) ) {
366 struct cons_space_object *cell_a = &pointer2cell( a );
367 struct cons_space_object *cell_b = &pointer2cell( b );
368
369 result = equal_integer_integer( cell_a->payload.ratio.dividend,
370 cell_b->payload.ratio.dividend ) &&
371 equal_integer_integer( cell_a->payload.ratio.divisor,
372 cell_b->payload.ratio.divisor );
373 }
374
375 return result;
376}
377
378/**
379 * @brief convert a ratio to an equivalent long double.
380 *
381 * @param rat a pointer to a ratio.
382 * @return long double
383 */
384long double c_ratio_to_ld( struct cons_pointer rat ) {
385 long double result = NAN;
386
387 debug_print( L"\nc_ratio_to_ld: ", DEBUG_ARITH );
389
390 if ( ratiop( rat ) ) {
391 struct cons_space_object *cell_a = &pointer2cell( rat );
392 struct cons_pointer dv = cell_a->payload.ratio.divisor;
393 struct cons_space_object *dv_cell = &pointer2cell( dv );
394 struct cons_pointer dd = cell_a->payload.ratio.dividend;
395 struct cons_space_object *dd_cell = &pointer2cell( dd );
396
397 if ( nilp( dv_cell->payload.integer.more )
398 && nilp( dd_cell->payload.integer.more ) ) {
399 result =
400 ( ( long double ) dd_cell->payload.integer.value ) /
401 ( ( long double ) dv_cell->payload.integer.value );;
402 } else {
403 fwprintf( stderr,
404 L"real conversion is not yet implemented for bignums rationals." );
405 }
406 }
407
408 debug_printf( DEBUG_ARITH, L"\nc_ratio_to_ld returning %d\n", result );
409
410 return result;
411}
struct cons_pointer allocate_cell(uint32_t tag)
Allocates a cell with the specified tag.
Definition conspage.c:235
#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 c_string_to_lisp_symbol(wchar_t *symbol)
Return a lisp symbol representation of this wide character string.
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:104
void debug_printf(int level, wchar_t *format,...)
wprintf adapted for the debug logging system.
Definition debug.c:120
void debug_print(wchar_t *message, int level)
print this debug message to stderr, if verbosity matches level.
Definition debug.c:60
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:138
#define DEBUG_ARITH
Print messages debugging arithmetic operations.
Definition debug.h:31
#define DEBUG_ALLOC
Print messages debugging memory allocation.
Definition debug.h:24
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:28
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:496
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:328
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 location, struct cons_pointer payload, struct cons_pointer frame_pointer)
Throw an exception.
Definition lispops.c:1396
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:538
long double c_ratio_to_ld(struct cons_pointer rat)
convert a ratio to an equivalent long double.
Definition ratio.c:384
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:94
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:206
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:362
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:179
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:258
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:139
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:295
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:317
struct cons_pointer simplify_ratio(struct cons_pointer pointer)
ratio.h
Definition ratio.c:48