1 |
/* |
2 |
* Dimension implementation routines |
3 |
* by Tom Epperly |
4 |
* Part of Ascend |
5 |
* Version: $Revision: 1.9 $ |
6 |
* Version control file: $RCSfile: dimen.c,v $ |
7 |
* Date last modified: $Date: 1997/10/28 19:20:32 $ |
8 |
* Last modified by: $Author: mthomas $ |
9 |
* |
10 |
* This file is part of the Ascend Language Interpreter. |
11 |
* |
12 |
* Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly |
13 |
* |
14 |
* The Ascend Language Interpreter is free software; you can redistribute |
15 |
* it and/or modify it under the terms of the GNU General Public License as |
16 |
* published by the Free Software Foundation; either version 2 of the |
17 |
* License, or (at your option) any later version. |
18 |
* |
19 |
* The Ascend Language Interpreter is distributed in hope that it will be |
20 |
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
22 |
* General Public License for more details. |
23 |
* |
24 |
* You should have received a copy of the GNU General Public License |
25 |
* along with the program; if not, write to the Free Software Foundation, |
26 |
* Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named |
27 |
* COPYING. |
28 |
* |
29 |
*/ |
30 |
|
31 |
#include <utilities/ascConfig.h> |
32 |
#include "compiler.h" |
33 |
#include <utilities/ascPanic.h> |
34 |
#include <utilities/ascMalloc.h> |
35 |
#include <utilities/error.h> |
36 |
#include <general/list.h> |
37 |
#include "fractions.h" |
38 |
#include "dimen.h" |
39 |
#include <general/mathmacros.h> |
40 |
|
41 |
struct gl_list_t *g_dimen_list; |
42 |
dim_type *g_wild_dimen,*g_trig_dimen,*g_dimensionless; |
43 |
#ifndef lint |
44 |
static CONST char DimenID[] = "$Id: dimen.c,v 1.9 1997/10/28 19:20:32 mthomas Exp $"; |
45 |
#endif |
46 |
|
47 |
#define WILD(d) ((d)->wild & DIM_WILD) |
48 |
/* test a DIMENSION pointer for being wild or not */ |
49 |
|
50 |
char *DimNames[NUM_DIMENS]={ |
51 |
/* keep this structure current with defines in dimen.h */ |
52 |
"M", |
53 |
"Q", |
54 |
"L", |
55 |
"T", |
56 |
"TMP", |
57 |
"C", |
58 |
"E", |
59 |
"LUM", |
60 |
"P", |
61 |
"S" |
62 |
}; |
63 |
|
64 |
|
65 |
void InitDimenList(void) |
66 |
{ |
67 |
/* FPRINTF(ASCERR,"INITIALISING DIMENSION LIST\n"); */ |
68 |
|
69 |
g_dimen_list = gl_create(200L); |
70 |
AssertMemory(g_dimen_list); |
71 |
g_wild_dimen = (dim_type *)ascmalloc((unsigned)sizeof(dim_type)); |
72 |
AssertAllocatedMemory(g_wild_dimen,sizeof(dim_type)); |
73 |
g_trig_dimen = (dim_type *)ascmalloc((unsigned)sizeof(dim_type)); |
74 |
AssertAllocatedMemory(g_trig_dimen,sizeof(dim_type)); |
75 |
g_dimensionless = (dim_type *)ascmalloc((unsigned)sizeof(dim_type)); |
76 |
AssertAllocatedMemory(g_dimensionless,sizeof(dim_type)); |
77 |
assert((g_wild_dimen!=NULL)&&(g_dimensionless!=NULL)&&(g_trig_dimen!=NULL)); |
78 |
ClearDimensions(g_wild_dimen); |
79 |
ClearDimensions(g_trig_dimen); |
80 |
ClearDimensions(g_dimensionless); |
81 |
g_dimensionless->wild=0; |
82 |
g_wild_dimen->wild = DIM_WILD; |
83 |
g_trig_dimen->wild = 0; |
84 |
SetDimFraction(*g_trig_dimen,D_PLANE_ANGLE, |
85 |
CreateFraction((FRACPART)1,(FRACPART)1)); |
86 |
gl_insert_sorted(g_dimen_list,g_dimensionless,(CmpFunc)CmpDimen); |
87 |
gl_insert_sorted(g_dimen_list,g_wild_dimen,(CmpFunc)CmpDimen); |
88 |
gl_insert_sorted(g_dimen_list,g_trig_dimen,(CmpFunc)CmpDimen); |
89 |
} |
90 |
|
91 |
void DestroyDimenList(void) |
92 |
{ |
93 |
gl_free_and_destroy(g_dimen_list); |
94 |
g_wild_dimen = g_dimensionless = NULL; |
95 |
} |
96 |
|
97 |
int IsWild(CONST dim_type *d) |
98 |
{ |
99 |
if (d != NULL) { |
100 |
return (WILD(d)); |
101 |
} else { |
102 |
FPRINTF(ASCERR,"IsWild called on NULL dimension pointer\n"); |
103 |
return 1; |
104 |
} |
105 |
} |
106 |
|
107 |
int OddDimension(CONST dim_type *dimp) |
108 |
{ |
109 |
int i; |
110 |
if (!dimp || IsWild(dimp)) return 1; |
111 |
for (i=0;i<NUM_DIMENS;i++) |
112 |
if (Denominator(GetDimFraction(*dimp,i))!=1 || |
113 |
(Numerator(GetDimFraction(*dimp,i))%2) ) |
114 |
return 1; |
115 |
return 0; |
116 |
} |
117 |
|
118 |
/* return 1 if fractional, null or wild, 0 otherwise */ |
119 |
static int FractionalDimension(CONST dim_type *dimp) |
120 |
{ |
121 |
int i; |
122 |
if (!dimp || IsWild(dimp)) return 1; |
123 |
for (i=0;i<NUM_DIMENS;i++) |
124 |
if (Denominator(GetDimFraction(*dimp,i))!=1) return 1; |
125 |
return 0; |
126 |
} |
127 |
|
128 |
int NonCubicDimension(CONST dim_type *dimp) |
129 |
{ |
130 |
int i; |
131 |
if (!dimp || IsWild(dimp)) return 1; |
132 |
for (i=0;i<NUM_DIMENS;i++) |
133 |
if (Denominator(GetDimFraction(*dimp,i))!=1 || |
134 |
(Numerator(GetDimFraction(*dimp,i))%3) ) |
135 |
return 1; |
136 |
return 0; |
137 |
} |
138 |
|
139 |
void CopyDimensions(CONST dim_type *src, dim_type *dest) |
140 |
{ |
141 |
*dest = *src; |
142 |
} |
143 |
|
144 |
CONST dim_type *SquareDimension(CONST dim_type *dim, int check) |
145 |
{ |
146 |
if (!dim) return NULL; |
147 |
if (IsWild(dim)) return WildDimension(); |
148 |
if (check && FractionalDimension(dim)) return NULL; |
149 |
else { |
150 |
dim_type d; |
151 |
struct fraction sqr=CreateFraction((FRACPART)2,(FRACPART)1); |
152 |
d=ScaleDimensions(dim,sqr); |
153 |
return (FindOrAddDimen(&d)); |
154 |
} |
155 |
} |
156 |
|
157 |
CONST dim_type *HalfDimension(CONST dim_type *dim, int check) |
158 |
{ |
159 |
if (!dim) return NULL; |
160 |
if (IsWild(dim)) return WildDimension(); |
161 |
if (check && OddDimension(dim)) return NULL; |
162 |
else { |
163 |
dim_type d; |
164 |
struct fraction half=CreateFraction((FRACPART)1,(FRACPART)2); |
165 |
d=ScaleDimensions(dim,half); |
166 |
return (FindOrAddDimen(&d)); |
167 |
} |
168 |
} |
169 |
|
170 |
CONST dim_type *CubeDimension(CONST dim_type *dim, int check) |
171 |
{ |
172 |
if (!dim) return NULL; |
173 |
if (IsWild(dim)) return WildDimension(); |
174 |
if (check && FractionalDimension(dim)) return NULL; |
175 |
else { |
176 |
dim_type d; |
177 |
struct fraction cub=CreateFraction((FRACPART)3,(FRACPART)1); |
178 |
d=ScaleDimensions(dim,cub); |
179 |
return (FindOrAddDimen(&d)); |
180 |
} |
181 |
} |
182 |
|
183 |
static FRACPART topmax(CONST dim_type *dim) { |
184 |
int i; |
185 |
FRACPART biggest = 0; |
186 |
for (i=0;i<NUM_DIMENS;i++) { |
187 |
biggest = MAX(ABS(Numerator(GetDimFraction(*dim,i))),biggest); |
188 |
} |
189 |
return biggest; |
190 |
} |
191 |
|
192 |
CONST dim_type *PowDimension(long mult, CONST dim_type *dim, int check) |
193 |
{ |
194 |
if (!dim) return NULL; |
195 |
if (IsWild(dim)) return dim; |
196 |
if (dim==Dimensionless()) return dim; |
197 |
if (check && FractionalDimension(dim)) return NULL; |
198 |
if ((long)FRACMAX < mult*topmax(dim)) return NULL; |
199 |
else { |
200 |
dim_type d; |
201 |
struct fraction new; |
202 |
new = CreateFraction((FRACPART)mult,(FRACPART)1); |
203 |
d = ScaleDimensions(dim,new); |
204 |
return (FindOrAddDimen(&d)); |
205 |
} |
206 |
} |
207 |
|
208 |
CONST dim_type *ThirdDimension(CONST dim_type *dim, int check) |
209 |
{ |
210 |
if (!dim) return NULL; |
211 |
if (IsWild(dim)) return WildDimension(); |
212 |
if (check && NonCubicDimension(dim)) return NULL; |
213 |
else { |
214 |
dim_type d; |
215 |
struct fraction third=CreateFraction((FRACPART)1,(FRACPART)3); |
216 |
d=ScaleDimensions(dim,third); |
217 |
return (FindOrAddDimen(&d)); |
218 |
} |
219 |
} |
220 |
|
221 |
void SetWild(dim_type *dim) |
222 |
{ |
223 |
assert(dim!=NULL); |
224 |
dim->wild=DIM_WILD; |
225 |
} |
226 |
|
227 |
int SameDimen(CONST dim_type *d1, CONST dim_type *d2) |
228 |
{ |
229 |
assert(d1!=NULL); |
230 |
assert(d2!=NULL); |
231 |
|
232 |
if (d1==d2 || (WILD(d1) && WILD(d2)) ) return 1; |
233 |
/* same pointer or both wild return now */ |
234 |
|
235 |
if ( WILD(d1) || WILD(d2) ) return 0; |
236 |
/* one is wild, other not, so punt */ |
237 |
|
238 |
return ( memcmp((char *)d1->f,(char *)d2->f, |
239 |
(sizeof(struct fraction)*NUM_DIMENS)) ==0 ); |
240 |
} |
241 |
|
242 |
int CmpDimen(CONST dim_type *d1, CONST dim_type *d2) |
243 |
{ |
244 |
register unsigned c; |
245 |
register int i; |
246 |
assert(d1!=NULL); |
247 |
assert(d2!=NULL); |
248 |
if (WILD(d1)) { |
249 |
if (WILD(d2)) { |
250 |
return 0; |
251 |
} else { |
252 |
return -1; |
253 |
} |
254 |
} |
255 |
if (WILD(d2)) { return 1; } |
256 |
for(c=0;c<NUM_DIMENS;c++) { |
257 |
i = CmpF( GetDimFraction(*d1,c), GetDimFraction(*d2,c) ); |
258 |
if (i<0) { |
259 |
return -1; |
260 |
} else { |
261 |
if (i>0) { |
262 |
return 1; |
263 |
} |
264 |
/* else continue to next dimen */ |
265 |
} |
266 |
} |
267 |
return 0; |
268 |
} |
269 |
|
270 |
void ClearDimensions(dim_type *d) |
271 |
{ |
272 |
register unsigned c; |
273 |
struct fraction f; |
274 |
assert(d!=NULL); |
275 |
f = CreateFraction((FRACPART)0,(FRACPART)1); |
276 |
d->wild = 0; |
277 |
for(c=0;c<NUM_DIMENS;c++) |
278 |
SetDimFraction(*d,c,f); |
279 |
} |
280 |
|
281 |
CONST dim_type *Dimensionless(void) |
282 |
{ |
283 |
AssertAllocatedMemory(g_dimensionless,sizeof(dim_type)); |
284 |
return g_dimensionless; |
285 |
} |
286 |
|
287 |
CONST dim_type *TrigDimension(void) |
288 |
{ |
289 |
AssertAllocatedMemory(g_trig_dimen,sizeof(dim_type)); |
290 |
return g_trig_dimen; |
291 |
} |
292 |
|
293 |
CONST dim_type *WildDimension(void) |
294 |
{ |
295 |
AssertAllocatedMemory(g_wild_dimen,sizeof(dim_type)); |
296 |
return g_wild_dimen; |
297 |
} |
298 |
|
299 |
static |
300 |
dim_type *CopyDimen(register CONST dim_type *d) |
301 |
{ |
302 |
register dim_type *result; |
303 |
assert(d!=NULL); |
304 |
result = (dim_type *)ascmalloc((unsigned)sizeof(dim_type)); |
305 |
ascbcopy((char *)d,(char *)result,sizeof(dim_type)); |
306 |
AssertAllocatedMemory(result,sizeof(dim_type)); |
307 |
return result; |
308 |
} |
309 |
|
310 |
CONST dim_type *FindOrAddDimen(CONST dim_type *d) |
311 |
{ |
312 |
register unsigned long place; |
313 |
register dim_type *result; |
314 |
if ((place=gl_search(g_dimen_list,d,(CmpFunc)CmpDimen))!=0){ |
315 |
result = gl_fetch(g_dimen_list,place); |
316 |
} |
317 |
else { |
318 |
result = CopyDimen(d); |
319 |
gl_insert_sorted(g_dimen_list,result,(CmpFunc)CmpDimen); |
320 |
} |
321 |
AssertAllocatedMemory(result,sizeof(dim_type)); |
322 |
return result; |
323 |
} |
324 |
|
325 |
dim_type AddDimensions(CONST dim_type *d1, CONST dim_type *d2) |
326 |
{ |
327 |
register unsigned c; |
328 |
dim_type result; |
329 |
ClearDimensions(&result); |
330 |
if (WILD(d1)||WILD(d2)) { |
331 |
result.wild = DIM_WILD; |
332 |
} else { |
333 |
for(c=0;c<NUM_DIMENS;c++) { |
334 |
SetDimFraction(result,c, |
335 |
AddF(GetDimFraction(*d1,c),GetDimFraction(*d2,c))); |
336 |
} |
337 |
} |
338 |
return result; |
339 |
} |
340 |
|
341 |
CONST dim_type *SumDimensions(CONST dim_type *d1, CONST dim_type *d2,int check) |
342 |
{ |
343 |
register unsigned c; |
344 |
dim_type result; |
345 |
if (check && (FractionalDimension(d1) || FractionalDimension(d2)) ) { |
346 |
return NULL; |
347 |
} |
348 |
ClearDimensions(&result); |
349 |
if (WILD(d1)||WILD(d2)) { |
350 |
return WildDimension(); |
351 |
} else { |
352 |
for(c=0;c<NUM_DIMENS;c++) { |
353 |
SetDimFraction(result,c, |
354 |
AddF(GetDimFraction(*d1,c),GetDimFraction(*d2,c))); |
355 |
} |
356 |
} |
357 |
return (FindOrAddDimen(&result)); |
358 |
} |
359 |
|
360 |
dim_type SubDimensions(CONST dim_type *d1, CONST dim_type *d2) |
361 |
{ |
362 |
register unsigned c; |
363 |
dim_type result; |
364 |
ClearDimensions(&result); |
365 |
if (WILD(d1)||WILD(d2)) { |
366 |
result.wild = DIM_WILD; |
367 |
} else { |
368 |
for(c=0;c<NUM_DIMENS;c++) { |
369 |
SetDimFraction(result,c, |
370 |
SubF(GetDimFraction(*d1,c),GetDimFraction(*d2,c))); |
371 |
} |
372 |
} |
373 |
return result; |
374 |
} |
375 |
|
376 |
CONST dim_type *DiffDimensions(CONST dim_type *d1, |
377 |
CONST dim_type *d2, |
378 |
int check) |
379 |
{ |
380 |
register unsigned c; |
381 |
dim_type result; |
382 |
if (check && (FractionalDimension(d1) || FractionalDimension(d2)) ){ |
383 |
return NULL; |
384 |
} |
385 |
ClearDimensions(&result); |
386 |
if (WILD(d1)||WILD(d2)) { |
387 |
return WildDimension(); |
388 |
} else { |
389 |
for(c=0;c<NUM_DIMENS;c++) { |
390 |
SetDimFraction(result,c, |
391 |
SubF(GetDimFraction(*d1,c),GetDimFraction(*d2,c))); |
392 |
} |
393 |
} |
394 |
return (FindOrAddDimen(&result)); |
395 |
} |
396 |
|
397 |
dim_type ScaleDimensions(CONST dim_type *dim, struct fraction frac) |
398 |
{ |
399 |
dim_type result; |
400 |
register unsigned c; |
401 |
result = *dim; |
402 |
if (result.wild & DIM_WILD) return result; |
403 |
for(c=0;c<NUM_DIMENS;c++) { |
404 |
SetDimFraction(result,c,MultF(frac,GetDimFraction(*dim,c))); |
405 |
} |
406 |
return result; |
407 |
} |
408 |
|
409 |
void PrintDimen(FILE *file, CONST dim_type *dim) |
410 |
{ |
411 |
int printed; |
412 |
if (WILD(dim)) { |
413 |
FPRINTF(file,"wild"); |
414 |
} else { |
415 |
int i; |
416 |
printed = 0; |
417 |
for (i=0;i<NUM_DIMENS; i++) { |
418 |
if (Numerator(dim->f[i])) { |
419 |
FPRINTF(file,"%d/%d%s ",Numerator(dim->f[i]),Denominator(dim->f[i]), |
420 |
DimName(i)); |
421 |
printed = 1; |
422 |
} |
423 |
} |
424 |
if (printed == 0) FPRINTF(file,"dimensionless"); |
425 |
} |
426 |
} |
427 |
|
428 |
ASC_DLLSPEC(void) PrintDimenMessage(CONST char *message |
429 |
, CONST char *label1, CONST dim_type *d1 |
430 |
, CONST char *label2, CONST dim_type *d2 |
431 |
){ |
432 |
/* |
433 |
error_reporter_start(ASC_USER_ERROR,NULL,0,NULL); |
434 |
FPRINTF(ASCERR,"%s: %s='", message, label1); |
435 |
PrintDimen(ASCERR,d1); |
436 |
FPRINTF(ASCERR,"', %s='",label2); |
437 |
PrintDimen(ASCERR,d2); |
438 |
FPRINTF(ASCERR,"'"); |
439 |
error_reporter_end_flush(); |
440 |
*/ |
441 |
ERROR_REPORTER_HERE(ASC_USER_ERROR,"Invalid dimensions"); |
442 |
} |
443 |
|
444 |
|
445 |
void DumpDimens(FILE *file) |
446 |
{ |
447 |
register unsigned long c,len; |
448 |
len = gl_length(g_dimen_list); |
449 |
FPRINTF(file,"Dimensions dump\n"); |
450 |
for(c=1;c<=len;c++) { |
451 |
PrintDimen(file,(dim_type *)gl_fetch(g_dimen_list,c)); |
452 |
PUTC('\n',file); |
453 |
} |
454 |
} |
455 |
|
456 |
CONST dim_type *CheckDimensionsMatch(CONST dim_type *d1, CONST dim_type *d2) |
457 |
{ |
458 |
if (WILD(d1)) return d2; |
459 |
if (WILD(d2)||d1 == d2) return d1; |
460 |
if (CmpDimen(d1,d2)==0) return d1; |
461 |
return NULL; |
462 |
} |
463 |
|
464 |
void ParseDim(dim_type *dim, CONST char *c) |
465 |
{ |
466 |
int i; |
467 |
assert((dim!=NULL)&&(c!=NULL)); |
468 |
ClearDimensions(dim); |
469 |
for( i=0; i<NUM_DIMENS && strcmp(c,DimNames[i]); i++ ) ; |
470 |
if( i>=NUM_DIMENS ) FPRINTF(ASCERR,"Dimension %s unknown.\n",c); |
471 |
else SetDimFraction(*dim,i,CreateFraction((FRACPART)1,(FRACPART)1)); |
472 |
} |
473 |
|
474 |
char *DimName(CONST int ndx) |
475 |
{ |
476 |
if( ndx >= 0 && ndx < NUM_DIMENS ) |
477 |
return( DimNames[ndx] ); |
478 |
else |
479 |
return NULL; |
480 |
} |