Subversion Repositories tendra.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1997
3
 
4
    This TenDRA(r) Computer Program is subject to Copyright
5
    owned by the United Kingdom Secretary of State for Defence
6
    acting through the Defence Evaluation and Research Agency
7
    (DERA).  It is made available to Recipients with a
8
    royalty-free licence for its use, reproduction, transfer
9
    to other parties and amendment for any purpose not excluding
10
    product development provided that any such use et cetera
11
    shall be deemed to be acceptance of the following conditions:-
12
 
13
        (1) Its Recipients shall ensure that this Notice is
14
        reproduced upon any copies or amended versions of it;
15
 
16
        (2) Any amended version of it shall be clearly marked to
17
        show both the nature of and the organisation responsible
18
        for the relevant amendment or amendments;
19
 
20
        (3) Its onward transfer from a recipient to another
21
        party shall be deemed to be that party's acceptance of
22
        these conditions;
23
 
24
        (4) DERA gives no warranty or assurance as to its
25
        quality or suitability for any purpose and DERA accepts
26
        no liability whatsoever in relation to any use to which
27
        it may be put.
28
*/
29
 
30
 
31
/*
32
**		INT64lib.pl
33
**		============
34
**
35
**  This file contains the pl_tdf definitions of
36
**  functions which perform floating-point to 64-bit
37
**  integer conversions.  Since there is a separate
38
**  function for each rounding mode, code is going
39
**  to be duplicated; for this reason, TDF tokens
40
**  have been used:
41
**
42
**    round_to_smaller: converts assuming 'towards_smaller'
43
**    fixup_difference: makes any necessary correction
44
**
45
**  The general format is as follows:
46
**
47
**	  i) Do error checking
48
**	 ii) Call 'round_to_smaller'
49
**	iii) Make correction with 'fixup_difference
50
**
51
**  (For the functions with rounding mode 'towards_smaller',
52
**   there is no need to make a correction.)
53
*/
54
 
55
 
56
 
57
#include "abstract.ph"
58
 
59
 
60
 
61
/* External declaration */
62
 
63
Iddec printf : proc;		/* definition provided by ANSI library */
64
Iddec print_bignum : proc;
65
Iddec print_sbignum : proc;
66
 
67
 
68
 
69
/*  TDFUshl is a C macro which is defined in the C file  */
70
/*  which implements the remaining functions in the 64-  */
71
/*  bit arithmetic library.  TDFC then outputs it as a   */
72
/*  TDF token, which is used in this file.               */
73
 
74
Tokdec TDFUshl : [EXP, EXP, EXP] EXP;
75
 
76
 
77
 
78
/*  Tokens for handling Error Treatments  */
79
 
80
 
81
/* DIV_ZERO_ERROR if distinct from OVERFLOW_ERROR, but the */
82
/* installers don't distinguish, so reflect this here.     */
83
 
84
Vardec __TDFerror : Int;
85
 
86
Tokdef OVERFLOW_ERROR = [] EXP  __TDFerror = -1(Int);
87
Tokdef DIV_ZERO_ERROR = [] EXP  OVERFLOW_ERROR;
88
/* Tokdef DIV_ZERO_ERROR = [] EXP  __TDFerror =  0(Int); */
89
Tokdef CLEAR_ERRORS   = [] EXP  __TDFerror =  1(Int);
90
 
91
 
92
 
93
/*  Tokens for rounding floating-point number to TDF_INT64  */
94
 
95
/* (Some of these error treatments must be 'continue', */
96
/*  and some of them may be 'impossible'.)             */
97
 
98
 
99
Tokdef Sround_to_smaller = [new_int:EXP, x:EXP] EXP
100
    {
101
	(new_int *+. .hi_32) = round_with_mode (continue, toward_smaller, ~INT32,
102
				floating_div (impossible,
103
					(*(BigFloat) x),
104
					4294967296.0(~BigFloat)));
105
 
106
	(new_int *+. .lo_32) = round_with_mode (continue, toward_smaller, ~UINT32,
107
				floating_minus (impossible,
108
					(*(BigFloat) x),
109
					floating_mult (impossible,
110
						float_int(impossible, ~BigFloat,
111
							hi_32[*(TDF_INT64) new_int]),
112
				    		4294967296.0(~BigFloat))))
113
    };
114
 
115
 
116
Tokdef Uround_to_smaller = [new_int:EXP, x:EXP] EXP
117
    {
118
	(new_int *+. .hi_u32) = round_with_mode (continue, toward_smaller, ~UINT32,
119
					floating_div (impossible,
120
						(*(BigFloat) x),
121
						4294967296.0(~BigFloat)));
122
 
123
	(new_int *+. .lo_u32) = round_with_mode (continue, toward_smaller, ~UINT32,
124
				   floating_minus (impossible,
125
					(*(BigFloat) x),
126
					floating_mult (impossible,
127
						float_int(impossible, ~BigFloat,
128
							hi_u32[*(TDF_INT64) new_int]),
129
				    		4294967296.0(~BigFloat))))
130
    };
131
 
132
 
133
 
134
/*  Tokens for making the correction  */
135
 
136
Tokdef Sfixup_difference = [new_int:EXP, x:EXP, MODE:ROUNDING_MODE] EXP
137
    Var new_float  : BigFloat
138
    Var difference : BigFloat
139
    {
140
	/* Construct the approximation */
141
	new_float = floating_plus (impossible,
142
			float_int (impossible, ~BigFloat, lo_32[*(TDF_INT64) new_int]),
143
			floating_mult (impossible,
144
				float_int (impossible, ~BigFloat, hi_32[*(TDF_INT64) new_int]),
145
				4294967296.0(~BigFloat)));
146
	difference = floating_minus (impossible,
147
			(*(BigFloat) x),
148
			(* new_float));
149
 
150
	? { ? { F? ((*(BigFloat) x) >= 0.0(~BigFloat));
151
		? (1(~INT32) == round_with_mode (continue, MODE, ~INT32,
152
					(* difference)) | L)
153
		|
154
	 	? (0(~INT32) == round_with_mode (continue, MODE, ~INT32,
155
				   floating_minus (impossible,
156
					(* difference),
157
					1.0(~BigFloat))) | L)
158
	    };
159
 
160
	    (new_int *+. .lo_32) = (lo_32[*(TDF_INT64) new_int] + 1(~UINT32));
161
 
162
	    ? (lo_32[*(TDF_INT64) new_int] == 0(~UINT32) | L);
163
	    (new_int *+. .hi_32) = (hi_32[*(TDF_INT64) new_int] + 1(~INT32))
164
 
165
	    | :L:	/* answer is correct - do nothing */
166
	    make_top
167
	};
168
    };
169
 
170
 
171
 
172
Tokdef Ufixup_difference = [new_int:EXP, x:EXP, MODE:ROUNDING_MODE] EXP
173
    Var new_float  : BigFloat
174
    Var difference : BigFloat
175
    {
176
	/* Construct the approximation */
177
	new_float = floating_plus (impossible,
178
			float_int (impossible, ~BigFloat, lo_u32[*(TDF_INT64) new_int]),
179
			floating_mult (impossible,
180
				float_int (impossible, ~BigFloat, hi_u32[*(TDF_INT64) new_int]),
181
				4294967296.0(~BigFloat)));
182
 
183
	difference = floating_minus (impossible, 
184
			(*(BigFloat) x),
185
			(* new_float));
186
 
187
	? { ? (1(~UINT32) == round_with_mode (continue, MODE, ~UINT32,
188
					* difference));
189
 
190
	    (new_int *+. .lo_u32) = (lo_u32[*(TDF_INT64) new_int] + 1(~UINT32));
191
	    ? (lo_u32[*(TDF_INT64) new_int] == 0(~UINT32));
192
	    (new_int *+. .hi_u32) = (hi_u32[*(TDF_INT64) new_int] + 1(~UINT32));
193
	  |
194
	    make_top	/* result is correct - do nothing */
195
	};
196
    };
197
 
198
 
199
 
200
 
201
 
202
 
203
 
204
 
205
	/* Procedures for SIGNED conversions */
206
 
207
/* SIGNED round_towards_negative_infinity */
208
 
209
Proc __TDFUs_R2NINF = INT64 (x:BigFloat)
210
    Var new_int : TDF_INT64
211
    {
212
	CLEAR_ERRORS;
213
	? { F? (* x <  9223372036854775808.0(~BigFloat));
214
	    F? (* x >= -9223372036854775808.0(~BigFloat));
215
	    |
216
	    OVERFLOW_ERROR
217
	};
218
 
219
	Sround_to_smaller [new_int, x];
220
	return (PARAM [* new_int])
221
    };
222
 
223
 
224
/* SIGNED round_towards_positive_infinity */
225
 
226
Proc __TDFUs_R2PINF = INT64 (x:BigFloat)
227
    Var new_int : TDF_INT64
228
    {
229
	CLEAR_ERRORS;
230
	? { F? (* x <= 9223372036854775807.0(~BigFloat));
231
	    F? (* x > -9223372036854775809.0(~BigFloat));
232
	    |
233
	    OVERFLOW_ERROR
234
	};
235
 
236
	? { F? (* x < -9223372036854775808.0(~BigFloat));	/* cannot round down */
237
	    (new_int *+. .lo_32) = 0(~UINT32); 
238
	    (new_int *+. .hi_32) = -2147483648(~INT32); 
239
	    |
240
	    Sround_to_smaller [new_int, x];
241
	    Sfixup_difference [new_int, x, toward_larger];
242
	};
243
 
244
	return (PARAM [* new_int])
245
    };
246
 
247
 
248
 
249
 
250
/* SIGNED round_to_nearest */
251
 
252
Proc __TDFUs_R2NEAR = INT64 (x:BigFloat)
253
    Var new_int : TDF_INT64
254
    {
255
	CLEAR_ERRORS;
256
 
257
	/* Use a strict test here else result is undefined */
258
	? { F? (* x <  9223372036854775807.5(~BigFloat));
259
	    F? (* x > -9223372036854775807.5(~BigFloat));
260
	    |
261
	    OVERFLOW_ERROR
262
	};
263
 
264
	? { F? (* x < -9223372036854775808.0(~BigFloat));	/* cannot round down */
265
	    (new_int *+. .lo_32) = 0(~UINT32); 
266
	    (new_int *+. .hi_32) = -2147483648(~INT32); 
267
	    |
268
	    Sround_to_smaller [new_int, x];
269
	    Sfixup_difference [new_int, x, to_nearest];
270
	};
271
 
272
	return (PARAM[* new_int])
273
    };
274
 
275
 
276
 
277
 
278
/* SIGNED round_to_zero */
279
 
280
Proc __TDFUs_R2ZERO = INT64 (x:BigFloat)
281
    Var new_int : TDF_INT64
282
    {
283
	CLEAR_ERRORS;
284
	? { F? (* x <  9223372036854775808.0(~BigFloat));
285
	    F? (* x > -9223372036854775809.0(~BigFloat));
286
	    |
287
	    OVERFLOW_ERROR
288
	};
289
 
290
	? { F? (* x < -9223372036854775808.0(~BigFloat));	/* cannot round down */
291
	    (new_int *+. .lo_32) = 0(~UINT32); 
292
	    (new_int *+. .hi_32) = -2147483648(~INT32); 
293
	    |
294
	    Sround_to_smaller [new_int, x];
295
	    Sfixup_difference [new_int, x, toward_zero];
296
	};
297
 
298
	return (PARAM[* new_int])
299
    };
300
 
301
 
302
 
303
/* SIGNED round_as_state */
304
 
305
Proc __TDFUs_ASSTATE = INT64 (x:BigFloat)
306
    Var new_int : TDF_INT64
307
    {
308
	CLEAR_ERRORS;
309
	? { F? (* x <  9223372036854775808.0(~BigFloat));
310
	    F? (* x > -9223372036854775809.0(~BigFloat));
311
	    |
312
	    OVERFLOW_ERROR
313
	};
314
 
315
	? { F? (* x < -9223372036854775808.0(~BigFloat));	/* cannot round down */
316
	    (new_int *+. .lo_32) = 0(~UINT32); 
317
	    (new_int *+. .hi_32) = -2147483648(~INT32); 
318
	    |
319
	    Sround_to_smaller [new_int, x];
320
	    Sfixup_difference [new_int, x, round_as_state];
321
	};
322
 
323
	return (PARAM[* new_int])
324
    };
325
 
326
 
327
 
328
 
329
 
330
 
331
	/* Procedures for UNSIGNED conversions */
332
 
333
/* UNSIGNED round_towards_negative_infinity */
334
 
335
Proc __TDFUu_R2NINF = UINT64 (x:BigFloat)
336
    Var new_int : TDF_INT64
337
    {
338
	CLEAR_ERRORS;
339
	? { F? (* x < 18446744073709551616.0(~BigFloat));
340
	    F? (* x >= 0.0(~BigFloat))
341
	    |
342
	    OVERFLOW_ERROR
343
	};
344
 
345
	Uround_to_smaller [new_int, x];
346
	return (UPARAM[* new_int])
347
    };
348
 
349
 
350
/* UNSIGNED round_towards_positive_infinity */
351
 
352
Proc __TDFUu_R2PINF = UINT64 (x:BigFloat)
353
    Var new_int : TDF_INT64
354
    {
355
	CLEAR_ERRORS;
356
	? { F? (* x <= 18446744073709551615.0(~BigFloat));
357
	    F? (* x > -1.0(~BigFloat))
358
	    |
359
	    OVERFLOW_ERROR
360
	};
361
 
362
	? { F? (* x < 0.0(~BigFloat));	/* cannot round down */
363
	    (new_int *+. .lo_u32) = 0(~UINT32); 
364
	    (new_int *+. .hi_u32) = 0(~UINT32); 
365
	    |
366
	    Uround_to_smaller [new_int, x];
367
	    Ufixup_difference [new_int, x, toward_larger];
368
	};
369
 
370
	return (UPARAM[* new_int])
371
    };
372
 
373
 
374
 
375
 
376
/* UNSIGNED round_to_nearest */
377
 
378
Proc __TDFUu_R2NEAR = UINT64 (x:BigFloat)
379
    Var new_int : TDF_INT64
380
    {
381
	CLEAR_ERRORS;
382
 
383
	/* Use a strict test here else result is undefined */
384
	? { F? (* x < 18446744073709551615.5(~BigFloat));
385
	    F? (* x > -0.5(~BigFloat))
386
	    |
387
	    OVERFLOW_ERROR
388
	};
389
 
390
	? { F? (* x < 0.0(~BigFloat));	/* cannot round down */
391
	    (new_int *+. .lo_u32) = 0(~UINT32); 
392
	    (new_int *+. .hi_u32) = 0(~UINT32); 
393
	    |
394
	    Uround_to_smaller [new_int, x];
395
	    Ufixup_difference [new_int, x, to_nearest];
396
	};
397
 
398
	return (UPARAM[* new_int])
399
    };
400
 
401
 
402
 
403
 
404
/* UNSIGNED round_to_zero */
405
 
406
Proc __TDFUu_R2ZERO = UINT64 (x:BigFloat)
407
    Var new_int : TDF_INT64
408
    {
409
	CLEAR_ERRORS;
410
	? { F? (* x < 18446744073709551616.0(~BigFloat));
411
	    F? (* x > -1.0(~BigFloat))
412
	    |
413
	    OVERFLOW_ERROR
414
	};
415
 
416
	? { F? (* x < 0.0(~BigFloat));	/* cannot round down */
417
	    (new_int *+. .lo_u32) = 0(~UINT32); 
418
	    (new_int *+. .hi_u32) = 0(~UINT32); 
419
	    |
420
	    Uround_to_smaller [new_int, x];
421
	    Ufixup_difference [new_int, x, toward_zero];
422
	};
423
 
424
	return (UPARAM[* new_int])
425
    };
426
 
427
 
428
 
429
 
430
/* UNSIGNED round_as_state */
431
 
432
Proc __TDFUu_ASSTATE = UINT64 (x:BigFloat)
433
    Var new_int : TDF_INT64
434
    {
435
	CLEAR_ERRORS;
436
	? { F? (* x < 18446744073709551616.0(~BigFloat));
437
	    F? (* x > -1.0(~BigFloat))
438
	    |
439
	    OVERFLOW_ERROR
440
	};
441
 
442
	? { F? (* x < 0.0(~BigFloat));	/* cannot round down */
443
	    (new_int *+. .lo_u32) = 0(~UINT32); 
444
	    (new_int *+. .hi_u32) = 0(~UINT32); 
445
	    |
446
	    Uround_to_smaller [new_int, x];
447
	    Ufixup_difference [new_int, x, round_as_state];
448
	};
449
 
450
	return (UPARAM[* new_int])
451
    };
452
 
453
 
454
 
455
 
456
 
457
 
458
/*
459
**	__TDFUs_float
460
**
461
**  Ian Currie suggested this, and I think it works:
462
**  The identity:
463
**		  a = 2^32 * lo(a) + lo(a)
464
**  holds for all a.
465
**  When a is negative, there is no loss of accuracy
466
**  due to loss of relative accuracy since both numbers
467
**  are stored exactly and as long as truncation doesn't
468
**  occur, the result will be exact.  Truncation itself
469
**  might theoretically be a problem: consider
470
**
471
**  		(0xf8000000, n)  	(where n!=0)
472
**
473
**  Here, the significant word is: -0x8000000, so the
474
**  calculation:
475
**
476
**	-0x8000000 * 2^32 + n
477
**
478
**  discards a certain number of bits when n is
479
**  denormalised before the addition.  On the other
480
**  hand, by converting the number to a positive value
481
**  before doing the conversion, it becomes:
482
**
483
**	0x7ffffff * 2^32 + (2^32-n)
484
**
485
**  The number of bits discarded from (2^32-n) is one
486
**  less than the number discarded above from n, and so
487
**  this appears to give more accuracy in the result.
488
**  However, this does not seem to occur in practice.
489
*/
490
 
491
/* None of the floating-point operations here will overflow */
492
 
493
Proc __TDFUs_float = BigFloat (param_a:INT64)
494
    Var a : TDF_INT64
495
    {
496
	(a *+. .PARAM) = (* param_a);
497
	CLEAR_ERRORS;
498
 
499
	Let lo_float = float_int (impossible, ~BigFloat, lo_32[* a])
500
	Let hi_float = float_int (impossible, ~BigFloat, hi_32[* a])
501
	{
502
	    return  (floating_plus (impossible,
503
			lo_float,
504
			floating_mult (impossible,
505
				hi_float,
506
				4294967296.0(~BigFloat))));
507
	}
508
    };
509
 
510
 
511
 
512
 
513
/*
514
**	__TDFUu_float
515
**
516
**  No errors here since each 64-bit integer is
517
**  representable by a 'BIG_FLOAT'.
518
**
519
*/
520
 
521
Proc __TDFUu_float = BigFloat (param_a:UINT64)
522
    Var a : TDF_INT64
523
    {
524
	(a *+. .UPARAM) = (* param_a);
525
	CLEAR_ERRORS;
526
 
527
	Let lo_float = float_int (impossible, ~BigFloat, lo_u32[* a])
528
	Let hi_float = float_int (impossible, ~BigFloat, hi_u32[* a])
529
	{
530
	    return  (floating_plus (impossible,
531
			lo_float,
532
			floating_mult (impossible,
533
				hi_float,
534
				4294967296.0(~BigFloat))));
535
	}
536
    };
537
 
538
 
539
 
540
 
541
/*
542
** 	__TDFUs_shl:
543
**
544
**  If n=64, the result overflows unless a=0.
545
**  Otherwise, checks that the top (n+1) bits
546
**  are identical - necessary to avoid overflow.
547
**  Implements an unsigned shift.
548
*/
549
 
550
Proc __TDFUs_shl = INT64 (param_a:INT64, n:UINT32)
551
    Var a : TDF_INT64
552
    {
553
	(a *+. .PARAM) = (* param_a);
554
	CLEAR_ERRORS;
555
	? { ? ((* n) == 0(~UINT32));
556
	    return (* param_a)
557
	  |
558
	    make_top
559
	};
560
 
561
	? { ? ((* n) > 63(~UINT32));		/* This is undefined */
562
	    ? { ? (lo_32[* a] == 0(~UINT32));	/* unless a = 0      */
563
		? (hi_32[* a] == 0(~INT32));
564
	      |
565
		OVERFLOW_ERROR
566
	    };
567
 
568
	    return (PARAM[const_0])
569
	  |
570
	    make_top	/*  0 <= n < 64  */
571
	};
572
 
573
	Labelled {
574
		? ((* n) !< 32(~UINT32)		| L_small_shift);
575
		? (hi_32[* a] !>  0(~INT32)	| L_overflow);
576
		? (hi_32[* a] !< -1(~INT32)	| L_overflow);
577
		? (shift_right (change_variety (continue, ~INT32, lo_32[* a]),
578
				63(~UINT32) - (* n)) == hi_32[* a] | L_overflow)
579
 
580
	   | :L_small_shift:
581
		? (hi_32[* a] == shift_right (shift_left (continue,
582
			hi_32[* a], (* n)), (* n)) | L_overflow)
583
 
584
	   | :L_overflow:
585
		OVERFLOW_ERROR
586
	};
587
 
588
	TDFUshl [a, (* a), (* n)];
589
	return (PARAM[* a])
590
    };
591
 
592
 
593
 
594
Proc __TDFUs_shr = INT64 (param_a:INT64, n:UINT32)
595
    Var a : TDF_INT64
596
    Var new_int : TDF_INT64
597
    {
598
	(a *+. .PARAM) = (* param_a);
599
	CLEAR_ERRORS;
600
	? { ? (* n >= 32(~UINT32));
601
	    (new_int *+. .lo_32) = change_variety (impossible, ~UINT32, 
602
				 shift_right (hi_32[* a], (* n) - 32(~UINT32)));
603
	    ? { ? (hi_32[* a] < 0(~INT32));
604
		(new_int *+. .hi_32) = -1(~INT32)
605
		|
606
		(new_int *+. .hi_32) = 0(~INT32)
607
	    }
608
	  |
609
	    (new_int *+. .lo_32) = or (shift_right (lo_32[* a], (* n)),
610
				       change_variety (impossible, ~UINT32,
611
					   shift_left(continue, hi_32[* a],
612
						      32(~UINT32) - (* n))));
613
	    (new_int *+. .hi_32) = shift_right (hi_32[* a], (* n))
614
	};
615
	return (PARAM[* new_int])
616
    };
617
 
618
 
619
Keep (__TDFUs_R2PINF, __TDFUs_R2NINF, __TDFUs_R2NEAR, __TDFUs_R2ZERO, __TDFUs_ASSTATE,
620
      __TDFUu_R2PINF, __TDFUu_R2NINF, __TDFUu_R2NEAR, __TDFUu_R2ZERO, __TDFUu_ASSTATE,
621
      __TDFUs_float,  __TDFUu_float,  __TDFUs_shl,    __TDFUs_shr )