Post Scarcity
A prototype for a post scarcity programming environment
Loading...
Searching...
No Matches
equal.c
Go to the documentation of this file.
1/*
2 * equal.c
3 *
4 * Checks for shallow and deep equality
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#include <math.h>
11#include <stdbool.h>
12
13#include "memory/conspage.h"
15#include "arith/integer.h"
16#include "arith/peano.h"
17#include "arith/ratio.h"
18#include "debug.h"
19
20/**
21 * Shallow, and thus cheap, equality: true if these two objects are
22 * the same object, else false.
23 */
24bool eq( struct cons_pointer a, struct cons_pointer b ) {
25 return ( ( a.page == b.page ) && ( a.offset == b.offset ) );
26}
27
28/**
29 * True if the objects at these two cons pointers have the same tag, else false.
30 * @param a a pointer to a cons-space object;
31 * @param b another pointer to a cons-space object.
32 * @return true if the objects at these two cons pointers have the same tag,
33 * else false.
34 */
35bool same_type( struct cons_pointer a, struct cons_pointer b ) {
36 struct cons_space_object *cell_a = &pointer2cell( a );
37 struct cons_space_object *cell_b = &pointer2cell( b );
38
39 return cell_a->tag.value == cell_b->tag.value;
40}
41
42/**
43 * Some strings will be null terminated and some will be NIL terminated... ooops!
44 * @param string the string to test
45 * @return true if it's the end of a string.
46 */
47bool end_of_string( struct cons_pointer string ) {
48 return nilp( string ) ||
49 pointer2cell( string ).payload.string.character == '\0';
50}
51
52/**
53 * @brief compare two long doubles and returns true if they are the same to
54 * within a tolerance of one part in a billion.
55 *
56 * @param a
57 * @param b
58 * @return true if `a` and `b` are equal to within one part in a billion.
59 * @return false otherwise.
60 */
61bool equal_ld_ld( long double a, long double b ) {
62 long double fa = fabsl( a );
63 long double fb = fabsl( b );
64 /* difference of magnitudes */
65 long double diff = fabsl( fa - fb );
66 /* average magnitude of the two */
67 long double av = ( fa > fb ) ? ( fa - diff ) : ( fb - diff );
68 /* amount of difference we will tolerate for equality */
69 long double tolerance = av * 0.000000001;
70
71 bool result = ( fabsl( a - b ) < tolerance );
72
73 debug_printf( DEBUG_ARITH, L"\nequal_ld_ld returning %d\n", result );
74
75 return result;
76}
77
78/**
79 * @brief Private function, don't use. It depends on its arguments being
80 * numbers and doesn't sanity check them.
81 *
82 * @param a a lisp integer -- if it isn't an integer, things will break.
83 * @param b a lisp real -- if it isn't a real, things will break.
84 * @return true if the two numbers have equal value.
85 * @return false if they don't.
86 */
87bool equal_integer_real( struct cons_pointer a, struct cons_pointer b ) {
88 debug_print( L"\nequal_integer_real: ", DEBUG_ARITH );
90 debug_print( L" = ", DEBUG_ARITH );
92 bool result = false;
93 struct cons_space_object *cell_a = &pointer2cell( a );
94 struct cons_space_object *cell_b = &pointer2cell( b );
95
96 if ( nilp( cell_a->payload.integer.more ) ) {
97 result =
98 equal_ld_ld( ( long double ) cell_a->payload.integer.value,
99 cell_b->payload.real.value );
100 } else {
101 fwprintf( stderr,
102 L"\nequality is not yet implemented for bignums compared to reals." );
103 }
104
105 debug_printf( DEBUG_ARITH, L"\nequal_integer_real returning %d\n",
106 result );
107
108 return result;
109}
110
111/**
112 * @brief Private function, don't use. It depends on its arguments being
113 * numbers and doesn't sanity check them.
114 *
115 * @param a a lisp integer -- if it isn't an integer, things will break.
116 * @param b a lisp number.
117 * @return true if the two numbers have equal value.
118 * @return false if they don't.
119 */
121 debug_print( L"\nequal_integer_number: ", DEBUG_ARITH );
123 debug_print( L" = ", DEBUG_ARITH );
125 bool result = false;
126 struct cons_space_object *cell_b = &pointer2cell( b );
127
128 switch ( cell_b->tag.value ) {
129 case INTEGERTV:
130 result = equal_integer_integer( a, b );
131 break;
132 case REALTV:
133 result = equal_integer_real( a, b );
134 break;
135 case RATIOTV:
136 result = false;
137 break;
138 }
139
140 debug_printf( DEBUG_ARITH, L"\nequal_integer_number returning %d\n",
141 result );
142
143 return result;
144}
145
146/**
147 * @brief Private function, don't use. It depends on its arguments being
148 * numbers and doesn't sanity check them.
149 *
150 * @param a a lisp real -- if it isn't an real, things will break.
151 * @param b a lisp number.
152 * @return true if the two numbers have equal value.
153 * @return false if they don't.
154 */
155bool equal_real_number( struct cons_pointer a, struct cons_pointer b ) {
156 debug_print( L"\nequal_real_number: ", DEBUG_ARITH );
158 debug_print( L" = ", DEBUG_ARITH );
160 bool result = false;
161 struct cons_space_object *cell_b = &pointer2cell( b );
162
163 switch ( cell_b->tag.value ) {
164 case INTEGERTV:
165 result = equal_integer_real( b, a );
166 break;
167 case REALTV:{
168 struct cons_space_object *cell_a = &pointer2cell( a );
169 result =
170 equal_ld_ld( cell_a->payload.real.value,
171 cell_b->payload.real.value );
172 }
173 break;
174 case RATIOTV:
175 struct cons_space_object *cell_a = &pointer2cell( a );
176 result =
177 equal_ld_ld( c_ratio_to_ld( b ), cell_a->payload.real.value );
178 break;
179 }
180
181 debug_printf( DEBUG_ARITH, L"\nequal_real_number returning %d\n", result );
182
183 return result;
184}
185
186/**
187 * @brief Private function, don't use. It depends on its arguments being
188 * numbers and doesn't sanity check them.
189 *
190 * @param a a number
191 * @param b a number
192 * @return true if the two numbers have equal value.
193 * @return false if they don't.
194 */
196 bool result = eq( a, b );
197
198 debug_print( L"\nequal_number_number: ", DEBUG_ARITH );
200 debug_print( L" = ", DEBUG_ARITH );
202
203 if ( !result ) {
204 struct cons_space_object *cell_a = &pointer2cell( a );
205 struct cons_space_object *cell_b = &pointer2cell( b );
206
207 switch ( cell_a->tag.value ) {
208 case INTEGERTV:
209 result = equal_integer_number( a, b );
210 break;
211 case REALTV:
212 result = equal_real_number( a, b );
213 break;
214 case RATIOTV:
215 switch ( cell_b->tag.value ) {
216 case INTEGERTV:
217 /* as all ratios are simplified by make_ratio, any
218 * ratio that would simplify to an integer is an
219 * integer, */
220 result = false;
221 break;
222 case REALTV:
223 result = equal_real_number( b, a );
224 break;
225 case RATIOTV:
226 result = equal_ratio_ratio( a, b );
227 break;
228 /* can't throw an exception from here, but non-numbers
229 * shouldn't have been passed in anyway, so no default. */
230 }
231 break;
232 /* can't throw an exception from here, but non-numbers
233 * shouldn't have been passed in anyway, so no default. */
234 }
235 }
236
237 debug_printf( DEBUG_ARITH, L"\nequal_number_number returning %d\n",
238 result );
239
240 return result;
241}
242
243/**
244 * Deep, and thus expensive, equality: true if these two objects have
245 * identical structure, else false.
246 */
247bool equal( struct cons_pointer a, struct cons_pointer b ) {
248 debug_print( L"\nequal: ", DEBUG_ARITH );
250 debug_print( L" = ", DEBUG_ARITH );
252
253 bool result = eq( a, b );
254
255 if ( !result && same_type( a, b ) ) {
256 struct cons_space_object *cell_a = &pointer2cell( a );
257 struct cons_space_object *cell_b = &pointer2cell( b );
258
259 switch ( cell_a->tag.value ) {
260 case CONSTV:
261 case LAMBDATV:
262 case NLAMBDATV:
263 /* TODO: it is not OK to do this on the stack since list-like
264 * structures can be of indefinite extent. It *must* be done by
265 * iteration (and even that is problematic) */
266 result =
267 equal( cell_a->payload.cons.car, cell_b->payload.cons.car )
268 && equal( cell_a->payload.cons.cdr,
269 cell_b->payload.cons.cdr );
270 break;
271 case KEYTV:
272 case STRINGTV:
273 case SYMBOLTV:
274 /* slightly complex because a string may or may not have a '\0'
275 * cell at the end, but I'll ignore that for now. I think in
276 * practice only the empty string will.
277 */
278 /* TODO: it is not OK to do this on the stack since list-like
279 * structures can be of indefinite extent. It *must* be done by
280 * iteration (and even that is problematic) */
281 result =
282 cell_a->payload.string.hash == cell_b->payload.string.hash
283 && cell_a->payload.string.character ==
284 cell_b->payload.string.character
285 &&
286 ( equal
287 ( cell_a->payload.string.cdr,
288 cell_b->payload.string.cdr )
289 || ( end_of_string( cell_a->payload.string.cdr )
290 && end_of_string( cell_b->payload.string.cdr ) ) );
291 break;
292 case INTEGERTV:
293 result =
294 ( cell_a->payload.integer.value ==
295 cell_b->payload.integer.value ) &&
296 equal( cell_a->payload.integer.more,
297 cell_b->payload.integer.more );
298 break;
299 case RATIOTV:
300 result = equal_ratio_ratio( a, b );
301 break;
302 case REALTV:
303 {
304 double num_a = to_long_double( a );
305 double num_b = to_long_double( b );
306 double max = fabs( num_a ) > fabs( num_b )
307 ? fabs( num_a )
308 : fabs( num_b );
309
310 /*
311 * not more different than one part in a million - close enough
312 */
313 result = fabs( num_a - num_b ) < ( max / 1000000.0 );
314 }
315 break;
316 default:
317 result = false;
318 break;
319 }
320 } else if ( numberp( a ) && numberp( b ) ) {
321 result = equal_number_number( a, b );
322 }
323
324 /*
325 * there's only supposed ever to be one T and one NIL cell, so each
326 * should be caught by eq; equality of vector-space objects is a whole
327 * other ball game so we won't deal with it now (and indeed may never).
328 * I'm not certain what equality means for read and write streams, so
329 * I'll ignore them, too, for now.
330 */
331
332 debug_printf( DEBUG_ARITH, L"\nequal returning %d\n", result );
333
334 return result;
335}
#define KEYTV
The string KEYW, considered as an unsigned int.
#define SYMBOLTV
The string SYMB, considered as an unsigned int.
union cons_space_object::@2 tag
union cons_space_object::@3 payload
uint32_t page
the index of the page on which this cell resides
#define STRINGTV
The string STRG, considered as an unsigned int.
#define INTEGERTV
The string INTR, considered as an unsigned int.
#define RATIOTV
The string RTIO, considered as an unsigned int.
#define CONSTV
The string CONS, 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...
#define NLAMBDATV
The string NLMD, considered as an unsigned int.
uint32_t offset
the index of the cell within the page
#define REALTV
The string REAL, considered as an unsigned int.
#define LAMBDATV
The string LMDA, considered as an unsigned int.
#define pointer2cell(pointer)
given a cons_pointer as argument, return the cell.
#define numberp(conspoint)
true if conspoint points to some sort of a number cell, else false
An indirect pointer to a cons cell.
an object in cons space.
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
bool equal_ld_ld(long double a, long double b)
compare two long doubles and returns true if they are the same to within a tolerance of one part in a...
Definition equal.c:61
bool equal_integer_number(struct cons_pointer a, struct cons_pointer b)
Private function, don't use.
Definition equal.c:120
bool equal_number_number(struct cons_pointer a, struct cons_pointer b)
Private function, don't use.
Definition equal.c:195
bool same_type(struct cons_pointer a, struct cons_pointer b)
True if the objects at these two cons pointers have the same tag, else false.
Definition equal.c:35
bool equal_integer_real(struct cons_pointer a, struct cons_pointer b)
Private function, don't use.
Definition equal.c:87
bool end_of_string(struct cons_pointer string)
Some strings will be null terminated and some will be NIL terminated... ooops!
Definition equal.c:47
bool equal_real_number(struct cons_pointer a, struct cons_pointer b)
Private function, don't use.
Definition equal.c:155
bool equal(struct cons_pointer a, struct cons_pointer b)
Deep, and thus expensive, equality: true if these two objects have identical structure,...
Definition equal.c:247
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
long double to_long_double(struct cons_pointer arg)
Return the closest possible binary64 representation to the value of this arg, expected to be an integ...
Definition peano.c:124
long double c_ratio_to_ld(struct cons_pointer rat)
convert a ratio to an equivalent long double.
Definition ratio.c:379
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