Mercurial > projects > ldc
comparison lphobos/std/conv.d @ 131:5825d48b27d1 trunk
[svn r135] * Merged DMD 1.025 *
* Fixed a minor linking order mishap *
* Added an command line option -annotate *
* Fixed some problems with running optimizations *
* Added std.stdio and dependencies to lphobos (still not 100% working, but compiles and links) *
* Fixed problems with passing aggregate types to variadic functions *
* Added initial code towards full GC support, currently based on malloc and friends, not all the runtime calls the GC yet for memory *
* Fixed problems with resolving nested function context pointers for some heavily nested cases *
* Redid function argument passing + other minor code cleanups, still lots to do on this end... *
author | lindquist |
---|---|
date | Fri, 04 Jan 2008 01:38:42 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
130:a7dfa0ed966c | 131:5825d48b27d1 |
---|---|
1 | |
2 // Written in the D programming language. | |
3 | |
4 /* | |
5 * Copyright (C) 2002-2006 by Digital Mars, www.digitalmars.com | |
6 * Written by Walter Bright | |
7 * Some parts contributed by David L. Davis | |
8 * | |
9 * This software is provided 'as-is', without any express or implied | |
10 * warranty. In no event will the authors be held liable for any damages | |
11 * arising from the use of this software. | |
12 * | |
13 * Permission is granted to anyone to use this software for any purpose, | |
14 * including commercial applications, and to alter it and redistribute it | |
15 * freely, subject to the following restrictions: | |
16 * | |
17 * o The origin of this software must not be misrepresented; you must not | |
18 * claim that you wrote the original software. If you use this software | |
19 * in a product, an acknowledgment in the product documentation would be | |
20 * appreciated but is not required. | |
21 * o Altered source versions must be plainly marked as such, and must not | |
22 * be misrepresented as being the original software. | |
23 * o This notice may not be removed or altered from any source | |
24 * distribution. | |
25 */ | |
26 | |
27 /*********** | |
28 * Conversion building blocks. These differ from the C equivalents | |
29 * <tt>atoi()</tt> and <tt>atol()</tt> by | |
30 * checking for overflow and not allowing whitespace. | |
31 * | |
32 * For conversion to signed types, the grammar recognized is: | |
33 * <pre> | |
34 $(I Integer): | |
35 $(I Sign UnsignedInteger) | |
36 $(I UnsignedInteger) | |
37 | |
38 $(I Sign): | |
39 $(B +) | |
40 $(B -) | |
41 * </pre> | |
42 * For conversion to signed types, the grammar recognized is: | |
43 * <pre> | |
44 $(I UnsignedInteger): | |
45 $(I DecimalDigit) | |
46 $(I DecimalDigit) $(I UnsignedInteger) | |
47 * </pre> | |
48 * Macros: | |
49 * WIKI=Phobos/StdConv | |
50 */ | |
51 | |
52 module std.conv; | |
53 | |
54 private import std.string; // for atof(), toString() | |
55 private import std.c.stdlib; | |
56 private import std.math; // for fabs(), isnan() | |
57 private import std.stdio; // for writefln() and printf() | |
58 | |
59 | |
60 //debug=conv; // uncomment to turn on debugging printf's | |
61 | |
62 /* ************* Exceptions *************** */ | |
63 | |
64 /** | |
65 * Thrown on conversion errors, which happens on deviation from the grammar. | |
66 */ | |
67 class ConvError : Error | |
68 { | |
69 this(char[] s) | |
70 { | |
71 super("conversion " ~ s); | |
72 } | |
73 } | |
74 | |
75 private void conv_error(char[] s) | |
76 { | |
77 throw new ConvError(s); | |
78 } | |
79 | |
80 /** | |
81 * Thrown on conversion overflow errors. | |
82 */ | |
83 class ConvOverflowError : Error | |
84 { | |
85 this(char[] s) | |
86 { | |
87 super("Error: overflow " ~ s); | |
88 } | |
89 } | |
90 | |
91 private void conv_overflow(char[] s) | |
92 { | |
93 throw new ConvOverflowError(s); | |
94 } | |
95 | |
96 /*************************************************************** | |
97 * Convert character string to the return type. | |
98 */ | |
99 | |
100 int toInt(char[] s) | |
101 { | |
102 int length = s.length; | |
103 | |
104 if (!length) | |
105 goto Lerr; | |
106 | |
107 int sign = 0; | |
108 int v = 0; | |
109 | |
110 for (int i = 0; i < length; i++) | |
111 { | |
112 char c = s[i]; | |
113 if (c >= '0' && c <= '9') | |
114 { | |
115 if (v < int.max/10 || (v == int.max/10 && c + sign <= '7')) | |
116 v = v * 10 + (c - '0'); | |
117 else | |
118 goto Loverflow; | |
119 } | |
120 else if (c == '-' && i == 0) | |
121 { | |
122 sign = -1; | |
123 if (length == 1) | |
124 goto Lerr; | |
125 } | |
126 else if (c == '+' && i == 0) | |
127 { | |
128 if (length == 1) | |
129 goto Lerr; | |
130 } | |
131 else | |
132 goto Lerr; | |
133 } | |
134 if (sign == -1) | |
135 { | |
136 if (cast(uint)v > 0x80000000) | |
137 goto Loverflow; | |
138 v = -v; | |
139 } | |
140 else | |
141 { | |
142 if (cast(uint)v > 0x7FFFFFFF) | |
143 goto Loverflow; | |
144 } | |
145 return v; | |
146 | |
147 Loverflow: | |
148 conv_overflow(s); | |
149 | |
150 Lerr: | |
151 conv_error(s); | |
152 return 0; | |
153 } | |
154 | |
155 unittest | |
156 { | |
157 debug(conv) printf("conv.toInt.unittest\n"); | |
158 | |
159 int i; | |
160 | |
161 i = toInt("0"); | |
162 assert(i == 0); | |
163 | |
164 i = toInt("+0"); | |
165 assert(i == 0); | |
166 | |
167 i = toInt("-0"); | |
168 assert(i == 0); | |
169 | |
170 i = toInt("6"); | |
171 assert(i == 6); | |
172 | |
173 i = toInt("+23"); | |
174 assert(i == 23); | |
175 | |
176 i = toInt("-468"); | |
177 assert(i == -468); | |
178 | |
179 i = toInt("2147483647"); | |
180 assert(i == 0x7FFFFFFF); | |
181 | |
182 i = toInt("-2147483648"); | |
183 assert(i == 0x80000000); | |
184 | |
185 static char[][] errors = | |
186 [ | |
187 "", | |
188 "-", | |
189 "+", | |
190 "-+", | |
191 " ", | |
192 " 0", | |
193 "0 ", | |
194 "- 0", | |
195 "1-", | |
196 "xx", | |
197 "123h", | |
198 "2147483648", | |
199 "-2147483649", | |
200 "5656566565", | |
201 ]; | |
202 | |
203 for (int j = 0; j < errors.length; j++) | |
204 { | |
205 i = 47; | |
206 try | |
207 { | |
208 i = toInt(errors[j]); | |
209 printf("i = %d\n", i); | |
210 } | |
211 catch (Error e) | |
212 { | |
213 debug(conv) e.print(); | |
214 i = 3; | |
215 } | |
216 assert(i == 3); | |
217 } | |
218 } | |
219 | |
220 | |
221 /******************************************************* | |
222 * ditto | |
223 */ | |
224 | |
225 uint toUint(char[] s) | |
226 { | |
227 int length = s.length; | |
228 | |
229 if (!length) | |
230 goto Lerr; | |
231 | |
232 uint v = 0; | |
233 | |
234 for (int i = 0; i < length; i++) | |
235 { | |
236 char c = s[i]; | |
237 if (c >= '0' && c <= '9') | |
238 { | |
239 if (v < uint.max/10 || (v == uint.max/10 && c <= '5')) | |
240 v = v * 10 + (c - '0'); | |
241 else | |
242 goto Loverflow; | |
243 } | |
244 else | |
245 goto Lerr; | |
246 } | |
247 return v; | |
248 | |
249 Loverflow: | |
250 conv_overflow(s); | |
251 | |
252 Lerr: | |
253 conv_error(s); | |
254 return 0; | |
255 } | |
256 | |
257 unittest | |
258 { | |
259 debug(conv) printf("conv.toUint.unittest\n"); | |
260 | |
261 uint i; | |
262 | |
263 i = toUint("0"); | |
264 assert(i == 0); | |
265 | |
266 i = toUint("6"); | |
267 assert(i == 6); | |
268 | |
269 i = toUint("23"); | |
270 assert(i == 23); | |
271 | |
272 i = toUint("468"); | |
273 assert(i == 468); | |
274 | |
275 i = toUint("2147483647"); | |
276 assert(i == 0x7FFFFFFF); | |
277 | |
278 i = toUint("4294967295"); | |
279 assert(i == 0xFFFFFFFF); | |
280 | |
281 static char[][] errors = | |
282 [ | |
283 "", | |
284 "-", | |
285 "+", | |
286 "-+", | |
287 " ", | |
288 " 0", | |
289 "0 ", | |
290 "- 0", | |
291 "1-", | |
292 "+5", | |
293 "-78", | |
294 "xx", | |
295 "123h", | |
296 "4294967296", | |
297 ]; | |
298 | |
299 for (int j = 0; j < errors.length; j++) | |
300 { | |
301 i = 47; | |
302 try | |
303 { | |
304 i = toUint(errors[j]); | |
305 printf("i = %d\n", i); | |
306 } | |
307 catch (Error e) | |
308 { | |
309 debug(conv) e.print(); | |
310 i = 3; | |
311 } | |
312 assert(i == 3); | |
313 } | |
314 } | |
315 | |
316 /******************************************************* | |
317 * ditto | |
318 */ | |
319 | |
320 long toLong(char[] s) | |
321 { | |
322 int length = s.length; | |
323 | |
324 if (!length) | |
325 goto Lerr; | |
326 | |
327 int sign = 0; | |
328 long v = 0; | |
329 | |
330 for (int i = 0; i < length; i++) | |
331 { | |
332 char c = s[i]; | |
333 if (c >= '0' && c <= '9') | |
334 { | |
335 if (v < long.max/10 || (v == long.max/10 && c + sign <= '7')) | |
336 v = v * 10 + (c - '0'); | |
337 else | |
338 goto Loverflow; | |
339 } | |
340 else if (c == '-' && i == 0) | |
341 { | |
342 sign = -1; | |
343 if (length == 1) | |
344 goto Lerr; | |
345 } | |
346 else if (c == '+' && i == 0) | |
347 { | |
348 if (length == 1) | |
349 goto Lerr; | |
350 } | |
351 else | |
352 goto Lerr; | |
353 } | |
354 if (sign == -1) | |
355 { | |
356 if (cast(ulong)v > 0x8000000000000000) | |
357 goto Loverflow; | |
358 v = -v; | |
359 } | |
360 else | |
361 { | |
362 if (cast(ulong)v > 0x7FFFFFFFFFFFFFFF) | |
363 goto Loverflow; | |
364 } | |
365 return v; | |
366 | |
367 Loverflow: | |
368 conv_overflow(s); | |
369 | |
370 Lerr: | |
371 conv_error(s); | |
372 return 0; | |
373 } | |
374 | |
375 unittest | |
376 { | |
377 debug(conv) printf("conv.toLong.unittest\n"); | |
378 | |
379 long i; | |
380 | |
381 i = toLong("0"); | |
382 assert(i == 0); | |
383 | |
384 i = toLong("+0"); | |
385 assert(i == 0); | |
386 | |
387 i = toLong("-0"); | |
388 assert(i == 0); | |
389 | |
390 i = toLong("6"); | |
391 assert(i == 6); | |
392 | |
393 i = toLong("+23"); | |
394 assert(i == 23); | |
395 | |
396 i = toLong("-468"); | |
397 assert(i == -468); | |
398 | |
399 i = toLong("2147483647"); | |
400 assert(i == 0x7FFFFFFF); | |
401 | |
402 i = toLong("-2147483648"); | |
403 assert(i == -0x80000000L); | |
404 | |
405 i = toLong("9223372036854775807"); | |
406 assert(i == 0x7FFFFFFFFFFFFFFF); | |
407 | |
408 i = toLong("-9223372036854775808"); | |
409 assert(i == 0x8000000000000000); | |
410 | |
411 static char[][] errors = | |
412 [ | |
413 "", | |
414 "-", | |
415 "+", | |
416 "-+", | |
417 " ", | |
418 " 0", | |
419 "0 ", | |
420 "- 0", | |
421 "1-", | |
422 "xx", | |
423 "123h", | |
424 "9223372036854775808", | |
425 "-9223372036854775809", | |
426 ]; | |
427 | |
428 for (int j = 0; j < errors.length; j++) | |
429 { | |
430 i = 47; | |
431 try | |
432 { | |
433 i = toLong(errors[j]); | |
434 printf("l = %d\n", i); | |
435 } | |
436 catch (Error e) | |
437 { | |
438 debug(conv) e.print(); | |
439 i = 3; | |
440 } | |
441 assert(i == 3); | |
442 } | |
443 } | |
444 | |
445 | |
446 /******************************************************* | |
447 * ditto | |
448 */ | |
449 | |
450 ulong toUlong(char[] s) | |
451 { | |
452 int length = s.length; | |
453 | |
454 if (!length) | |
455 goto Lerr; | |
456 | |
457 ulong v = 0; | |
458 | |
459 for (int i = 0; i < length; i++) | |
460 { | |
461 char c = s[i]; | |
462 if (c >= '0' && c <= '9') | |
463 { | |
464 if (v < ulong.max/10 || (v == ulong.max/10 && c <= '5')) | |
465 v = v * 10 + (c - '0'); | |
466 else | |
467 goto Loverflow; | |
468 } | |
469 else | |
470 goto Lerr; | |
471 } | |
472 return v; | |
473 | |
474 Loverflow: | |
475 conv_overflow(s); | |
476 | |
477 Lerr: | |
478 conv_error(s); | |
479 return 0; | |
480 } | |
481 | |
482 unittest | |
483 { | |
484 debug(conv) printf("conv.toUlong.unittest\n"); | |
485 | |
486 ulong i; | |
487 | |
488 i = toUlong("0"); | |
489 assert(i == 0); | |
490 | |
491 i = toUlong("6"); | |
492 assert(i == 6); | |
493 | |
494 i = toUlong("23"); | |
495 assert(i == 23); | |
496 | |
497 i = toUlong("468"); | |
498 assert(i == 468); | |
499 | |
500 i = toUlong("2147483647"); | |
501 assert(i == 0x7FFFFFFF); | |
502 | |
503 i = toUlong("4294967295"); | |
504 assert(i == 0xFFFFFFFF); | |
505 | |
506 i = toUlong("9223372036854775807"); | |
507 assert(i == 0x7FFFFFFFFFFFFFFF); | |
508 | |
509 i = toUlong("18446744073709551615"); | |
510 assert(i == 0xFFFFFFFFFFFFFFFF); | |
511 | |
512 | |
513 static char[][] errors = | |
514 [ | |
515 "", | |
516 "-", | |
517 "+", | |
518 "-+", | |
519 " ", | |
520 " 0", | |
521 "0 ", | |
522 "- 0", | |
523 "1-", | |
524 "+5", | |
525 "-78", | |
526 "xx", | |
527 "123h", | |
528 "18446744073709551616", | |
529 ]; | |
530 | |
531 for (int j = 0; j < errors.length; j++) | |
532 { | |
533 i = 47; | |
534 try | |
535 { | |
536 i = toUlong(errors[j]); | |
537 printf("i = %d\n", i); | |
538 } | |
539 catch (Error e) | |
540 { | |
541 debug(conv) e.print(); | |
542 i = 3; | |
543 } | |
544 assert(i == 3); | |
545 } | |
546 } | |
547 | |
548 | |
549 /******************************************************* | |
550 * ditto | |
551 */ | |
552 | |
553 short toShort(char[] s) | |
554 { | |
555 int v = toInt(s); | |
556 | |
557 if (v != cast(short)v) | |
558 goto Loverflow; | |
559 | |
560 return cast(short)v; | |
561 | |
562 Loverflow: | |
563 conv_overflow(s); | |
564 return 0; | |
565 } | |
566 | |
567 unittest | |
568 { | |
569 debug(conv) printf("conv.toShort.unittest\n"); | |
570 | |
571 short i; | |
572 | |
573 i = toShort("0"); | |
574 assert(i == 0); | |
575 | |
576 i = toShort("+0"); | |
577 assert(i == 0); | |
578 | |
579 i = toShort("-0"); | |
580 assert(i == 0); | |
581 | |
582 i = toShort("6"); | |
583 assert(i == 6); | |
584 | |
585 i = toShort("+23"); | |
586 assert(i == 23); | |
587 | |
588 i = toShort("-468"); | |
589 assert(i == -468); | |
590 | |
591 i = toShort("32767"); | |
592 assert(i == 0x7FFF); | |
593 | |
594 i = toShort("-32768"); | |
595 assert(i == cast(short)0x8000); | |
596 | |
597 static char[][] errors = | |
598 [ | |
599 "", | |
600 "-", | |
601 "+", | |
602 "-+", | |
603 " ", | |
604 " 0", | |
605 "0 ", | |
606 "- 0", | |
607 "1-", | |
608 "xx", | |
609 "123h", | |
610 "32768", | |
611 "-32769", | |
612 ]; | |
613 | |
614 for (int j = 0; j < errors.length; j++) | |
615 { | |
616 i = 47; | |
617 try | |
618 { | |
619 i = toShort(errors[j]); | |
620 printf("i = %d\n", i); | |
621 } | |
622 catch (Error e) | |
623 { | |
624 debug(conv) e.print(); | |
625 i = 3; | |
626 } | |
627 assert(i == 3); | |
628 } | |
629 } | |
630 | |
631 | |
632 /******************************************************* | |
633 * ditto | |
634 */ | |
635 | |
636 ushort toUshort(char[] s) | |
637 { | |
638 uint v = toUint(s); | |
639 | |
640 if (v != cast(ushort)v) | |
641 goto Loverflow; | |
642 | |
643 return cast(ushort)v; | |
644 | |
645 Loverflow: | |
646 conv_overflow(s); | |
647 return 0; | |
648 } | |
649 | |
650 unittest | |
651 { | |
652 debug(conv) printf("conv.toUshort.unittest\n"); | |
653 | |
654 ushort i; | |
655 | |
656 i = toUshort("0"); | |
657 assert(i == 0); | |
658 | |
659 i = toUshort("6"); | |
660 assert(i == 6); | |
661 | |
662 i = toUshort("23"); | |
663 assert(i == 23); | |
664 | |
665 i = toUshort("468"); | |
666 assert(i == 468); | |
667 | |
668 i = toUshort("32767"); | |
669 assert(i == 0x7FFF); | |
670 | |
671 i = toUshort("65535"); | |
672 assert(i == 0xFFFF); | |
673 | |
674 static char[][] errors = | |
675 [ | |
676 "", | |
677 "-", | |
678 "+", | |
679 "-+", | |
680 " ", | |
681 " 0", | |
682 "0 ", | |
683 "- 0", | |
684 "1-", | |
685 "+5", | |
686 "-78", | |
687 "xx", | |
688 "123h", | |
689 "65536", | |
690 ]; | |
691 | |
692 for (int j = 0; j < errors.length; j++) | |
693 { | |
694 i = 47; | |
695 try | |
696 { | |
697 i = toUshort(errors[j]); | |
698 printf("i = %d\n", i); | |
699 } | |
700 catch (Error e) | |
701 { | |
702 debug(conv) e.print(); | |
703 i = 3; | |
704 } | |
705 assert(i == 3); | |
706 } | |
707 } | |
708 | |
709 | |
710 /******************************************************* | |
711 * ditto | |
712 */ | |
713 | |
714 byte toByte(char[] s) | |
715 { | |
716 int v = toInt(s); | |
717 | |
718 if (v != cast(byte)v) | |
719 goto Loverflow; | |
720 | |
721 return cast(byte)v; | |
722 | |
723 Loverflow: | |
724 conv_overflow(s); | |
725 return 0; | |
726 } | |
727 | |
728 unittest | |
729 { | |
730 debug(conv) printf("conv.toByte.unittest\n"); | |
731 | |
732 byte i; | |
733 | |
734 i = toByte("0"); | |
735 assert(i == 0); | |
736 | |
737 i = toByte("+0"); | |
738 assert(i == 0); | |
739 | |
740 i = toByte("-0"); | |
741 assert(i == 0); | |
742 | |
743 i = toByte("6"); | |
744 assert(i == 6); | |
745 | |
746 i = toByte("+23"); | |
747 assert(i == 23); | |
748 | |
749 i = toByte("-68"); | |
750 assert(i == -68); | |
751 | |
752 i = toByte("127"); | |
753 assert(i == 0x7F); | |
754 | |
755 i = toByte("-128"); | |
756 assert(i == cast(byte)0x80); | |
757 | |
758 static char[][] errors = | |
759 [ | |
760 "", | |
761 "-", | |
762 "+", | |
763 "-+", | |
764 " ", | |
765 " 0", | |
766 "0 ", | |
767 "- 0", | |
768 "1-", | |
769 "xx", | |
770 "123h", | |
771 "128", | |
772 "-129", | |
773 ]; | |
774 | |
775 for (int j = 0; j < errors.length; j++) | |
776 { | |
777 i = 47; | |
778 try | |
779 { | |
780 i = toByte(errors[j]); | |
781 printf("i = %d\n", i); | |
782 } | |
783 catch (Error e) | |
784 { | |
785 debug(conv) e.print(); | |
786 i = 3; | |
787 } | |
788 assert(i == 3); | |
789 } | |
790 } | |
791 | |
792 | |
793 /******************************************************* | |
794 * ditto | |
795 */ | |
796 | |
797 ubyte toUbyte(char[] s) | |
798 { | |
799 uint v = toUint(s); | |
800 | |
801 if (v != cast(ubyte)v) | |
802 goto Loverflow; | |
803 | |
804 return cast(ubyte)v; | |
805 | |
806 Loverflow: | |
807 conv_overflow(s); | |
808 return 0; | |
809 } | |
810 | |
811 unittest | |
812 { | |
813 debug(conv) printf("conv.toUbyte.unittest\n"); | |
814 | |
815 ubyte i; | |
816 | |
817 i = toUbyte("0"); | |
818 assert(i == 0); | |
819 | |
820 i = toUbyte("6"); | |
821 assert(i == 6); | |
822 | |
823 i = toUbyte("23"); | |
824 assert(i == 23); | |
825 | |
826 i = toUbyte("68"); | |
827 assert(i == 68); | |
828 | |
829 i = toUbyte("127"); | |
830 assert(i == 0x7F); | |
831 | |
832 i = toUbyte("255"); | |
833 assert(i == 0xFF); | |
834 | |
835 static char[][] errors = | |
836 [ | |
837 "", | |
838 "-", | |
839 "+", | |
840 "-+", | |
841 " ", | |
842 " 0", | |
843 "0 ", | |
844 "- 0", | |
845 "1-", | |
846 "+5", | |
847 "-78", | |
848 "xx", | |
849 "123h", | |
850 "256", | |
851 ]; | |
852 | |
853 for (int j = 0; j < errors.length; j++) | |
854 { | |
855 i = 47; | |
856 try | |
857 { | |
858 i = toUbyte(errors[j]); | |
859 printf("i = %d\n", i); | |
860 } | |
861 catch (Error e) | |
862 { | |
863 debug(conv) e.print(); | |
864 i = 3; | |
865 } | |
866 assert(i == 3); | |
867 } | |
868 } | |
869 | |
870 | |
871 /******************************************************* | |
872 * ditto | |
873 */ | |
874 | |
875 float toFloat(in char[] s) | |
876 { | |
877 float f; | |
878 char* endptr; | |
879 char* sz; | |
880 | |
881 //writefln("toFloat('%s')", s); | |
882 sz = toStringz(s); | |
883 if (std.ctype.isspace(*sz)) | |
884 goto Lerr; | |
885 | |
886 // BUG: should set __locale_decpoint to "." for DMC | |
887 | |
888 setErrno(0); | |
889 f = strtof(sz, &endptr); | |
890 if (getErrno() == ERANGE) | |
891 goto Lerr; | |
892 if (endptr && (endptr == s.ptr || *endptr != 0)) | |
893 goto Lerr; | |
894 | |
895 return f; | |
896 | |
897 Lerr: | |
898 conv_error(s ~ " not representable as a float"); | |
899 assert(0); | |
900 } | |
901 | |
902 unittest | |
903 { | |
904 debug( conv ) writefln( "conv.toFloat.unittest" ); | |
905 float f; | |
906 | |
907 f = toFloat( "123" ); | |
908 assert( f == 123f ); | |
909 f = toFloat( "+123" ); | |
910 assert( f == +123f ); | |
911 f = toFloat( "-123" ); | |
912 assert( f == -123f ); | |
913 f = toFloat( "123e+2" ); | |
914 assert( f == 123e+2f ); | |
915 | |
916 f = toFloat( "123e-2" ); | |
917 assert( f == 123e-2f ); | |
918 f = toFloat( "123." ); | |
919 assert( f == 123.f ); | |
920 f = toFloat( ".456" ); | |
921 assert( f == .456f ); | |
922 | |
923 // min and max | |
924 f = toFloat("1.17549e-38"); | |
925 assert(feq(cast(real)f, cast(real)1.17549e-38)); | |
926 assert(feq(cast(real)f, cast(real)float.min)); | |
927 f = toFloat("3.40282e+38"); | |
928 assert(toString(f) == toString(3.40282e+38)); | |
929 | |
930 // nan | |
931 f = toFloat("nan"); | |
932 assert(toString(f) == toString(float.nan)); | |
933 } | |
934 | |
935 /******************************************************* | |
936 * ditto | |
937 */ | |
938 | |
939 double toDouble(in char[] s) | |
940 { | |
941 double f; | |
942 char* endptr; | |
943 char* sz; | |
944 | |
945 //writefln("toDouble('%s')", s); | |
946 sz = toStringz(s); | |
947 if (std.ctype.isspace(*sz)) | |
948 goto Lerr; | |
949 | |
950 // BUG: should set __locale_decpoint to "." for DMC | |
951 | |
952 setErrno(0); | |
953 f = strtod(sz, &endptr); | |
954 if (getErrno() == ERANGE) | |
955 goto Lerr; | |
956 if (endptr && (endptr == s.ptr || *endptr != 0)) | |
957 goto Lerr; | |
958 | |
959 return f; | |
960 | |
961 Lerr: | |
962 conv_error(s ~ " not representable as a double"); | |
963 assert(0); | |
964 } | |
965 | |
966 unittest | |
967 { | |
968 debug( conv ) writefln( "conv.toDouble.unittest" ); | |
969 double d; | |
970 | |
971 d = toDouble( "123" ); | |
972 assert( d == 123 ); | |
973 d = toDouble( "+123" ); | |
974 assert( d == +123 ); | |
975 d = toDouble( "-123" ); | |
976 assert( d == -123 ); | |
977 d = toDouble( "123e2" ); | |
978 assert( d == 123e2); | |
979 d = toDouble( "123e-2" ); | |
980 assert( d == 123e-2 ); | |
981 d = toDouble( "123." ); | |
982 assert( d == 123. ); | |
983 d = toDouble( ".456" ); | |
984 assert( d == .456 ); | |
985 d = toDouble( "1.23456E+2" ); | |
986 assert( d == 1.23456E+2 ); | |
987 | |
988 // min and max | |
989 d = toDouble("2.22507e-308"); | |
990 assert(feq(cast(real)d, cast(real)2.22507e-308)); | |
991 assert(feq(cast(real)d, cast(real)double.min)); | |
992 d = toDouble("1.79769e+308"); | |
993 assert(toString(d) == toString(1.79769e+308)); | |
994 assert(toString(d) == toString(double.max)); | |
995 | |
996 // nan | |
997 d = toDouble("nan"); | |
998 assert(toString(d) == toString(double.nan)); | |
999 //assert(cast(real)d == cast(real)double.nan); | |
1000 } | |
1001 | |
1002 /******************************************************* | |
1003 * ditto | |
1004 */ | |
1005 real toReal(in char[] s) | |
1006 { | |
1007 real f; | |
1008 char* endptr; | |
1009 char* sz; | |
1010 | |
1011 //writefln("toReal('%s')", s); | |
1012 sz = toStringz(s); | |
1013 if (std.ctype.isspace(*sz)) | |
1014 goto Lerr; | |
1015 | |
1016 // BUG: should set __locale_decpoint to "." for DMC | |
1017 | |
1018 setErrno(0); | |
1019 f = strtold(sz, &endptr); | |
1020 if (getErrno() == ERANGE) | |
1021 goto Lerr; | |
1022 if (endptr && (endptr == s.ptr || *endptr != 0)) | |
1023 goto Lerr; | |
1024 | |
1025 return f; | |
1026 | |
1027 Lerr: | |
1028 conv_error(s ~ " not representable as a real"); | |
1029 assert(0); | |
1030 } | |
1031 | |
1032 unittest | |
1033 { | |
1034 debug(conv) writefln("conv.toReal.unittest"); | |
1035 real r; | |
1036 | |
1037 r = toReal("123"); | |
1038 assert(r == 123L); | |
1039 r = toReal("+123"); | |
1040 assert(r == 123L); | |
1041 r = toReal("-123"); | |
1042 assert(r == -123L); | |
1043 r = toReal("123e2"); | |
1044 assert(feq(r, 123e2L)); | |
1045 r = toReal("123e-2"); | |
1046 assert(feq(r, 1.23L)); | |
1047 r = toReal("123."); | |
1048 assert(r == 123L); | |
1049 r = toReal(".456"); | |
1050 assert(r == .456L); | |
1051 | |
1052 r = toReal("1.23456e+2"); | |
1053 assert(feq(r, 1.23456e+2L)); | |
1054 r = toReal(toString(real.max / 2L)); | |
1055 assert(toString(r) == toString(real.max / 2L)); | |
1056 | |
1057 // min and max | |
1058 r = toReal(toString(real.min)); | |
1059 assert(toString(r) == toString(real.min)); | |
1060 r = toReal(toString(real.max)); | |
1061 assert(toString(r) == toString(real.max)); | |
1062 | |
1063 // nan | |
1064 r = toReal("nan"); | |
1065 assert(toString(r) == toString(real.nan)); | |
1066 //assert(r == real.nan); | |
1067 | |
1068 r = toReal(toString(real.nan)); | |
1069 assert(toString(r) == toString(real.nan)); | |
1070 //assert(r == real.nan); | |
1071 } | |
1072 | |
1073 version (none) | |
1074 { /* These are removed for the moment because of concern about | |
1075 * what to do about the 'i' suffix. Should it be there? | |
1076 * Should it not? What about 'nan', should it be 'nani'? | |
1077 * 'infinity' or 'infinityi'? | |
1078 * Should it match what toString(ifloat) does with the 'i' suffix? | |
1079 */ | |
1080 | |
1081 /******************************************************* | |
1082 * ditto | |
1083 */ | |
1084 | |
1085 ifloat toIfloat(in char[] s) | |
1086 { | |
1087 return toFloat(s) * 1.0i; | |
1088 } | |
1089 | |
1090 unittest | |
1091 { | |
1092 debug(conv) writefln("conv.toIfloat.unittest"); | |
1093 ifloat ift; | |
1094 | |
1095 ift = toIfloat(toString(123.45)); | |
1096 assert(toString(ift) == toString(123.45i)); | |
1097 | |
1098 ift = toIfloat(toString(456.77i)); | |
1099 assert(toString(ift) == toString(456.77i)); | |
1100 | |
1101 // min and max | |
1102 ift = toIfloat(toString(ifloat.min)); | |
1103 assert(toString(ift) == toString(ifloat.min) ); | |
1104 assert(feq(cast(ireal)ift, cast(ireal)ifloat.min)); | |
1105 | |
1106 ift = toIfloat(toString(ifloat.max)); | |
1107 assert(toString(ift) == toString(ifloat.max)); | |
1108 assert(feq(cast(ireal)ift, cast(ireal)ifloat.max)); | |
1109 | |
1110 // nan | |
1111 ift = toIfloat("nani"); | |
1112 assert(cast(real)ift == cast(real)ifloat.nan); | |
1113 | |
1114 ift = toIfloat(toString(ifloat.nan)); | |
1115 assert(toString(ift) == toString(ifloat.nan)); | |
1116 assert(feq(cast(ireal)ift, cast(ireal)ifloat.nan)); | |
1117 } | |
1118 | |
1119 /******************************************************* | |
1120 * ditto | |
1121 */ | |
1122 | |
1123 idouble toIdouble(in char[] s) | |
1124 { | |
1125 return toDouble(s) * 1.0i; | |
1126 } | |
1127 | |
1128 unittest | |
1129 { | |
1130 debug(conv) writefln("conv.toIdouble.unittest"); | |
1131 idouble id; | |
1132 | |
1133 id = toIdouble(toString("123.45")); | |
1134 assert(id == 123.45i); | |
1135 | |
1136 id = toIdouble(toString("123.45e+302i")); | |
1137 assert(id == 123.45e+302i); | |
1138 | |
1139 // min and max | |
1140 id = toIdouble(toString(idouble.min)); | |
1141 assert(toString( id ) == toString(idouble.min)); | |
1142 assert(feq(cast(ireal)id.re, cast(ireal)idouble.min.re)); | |
1143 assert(feq(cast(ireal)id.im, cast(ireal)idouble.min.im)); | |
1144 | |
1145 id = toIdouble(toString(idouble.max)); | |
1146 assert(toString(id) == toString(idouble.max)); | |
1147 assert(feq(cast(ireal)id.re, cast(ireal)idouble.max.re)); | |
1148 assert(feq(cast(ireal)id.im, cast(ireal)idouble.max.im)); | |
1149 | |
1150 // nan | |
1151 id = toIdouble("nani"); | |
1152 assert(cast(real)id == cast(real)idouble.nan); | |
1153 | |
1154 id = toIdouble(toString(idouble.nan)); | |
1155 assert(toString(id) == toString(idouble.nan)); | |
1156 } | |
1157 | |
1158 /******************************************************* | |
1159 * ditto | |
1160 */ | |
1161 | |
1162 ireal toIreal(in char[] s) | |
1163 { | |
1164 return toReal(s) * 1.0i; | |
1165 } | |
1166 | |
1167 unittest | |
1168 { | |
1169 debug(conv) writefln("conv.toIreal.unittest"); | |
1170 ireal ir; | |
1171 | |
1172 ir = toIreal(toString("123.45")); | |
1173 assert(feq(cast(real)ir.re, cast(real)123.45i)); | |
1174 | |
1175 ir = toIreal(toString("123.45e+82i")); | |
1176 assert(toString(ir) == toString(123.45e+82i)); | |
1177 //assert(ir == 123.45e+82i); | |
1178 | |
1179 // min and max | |
1180 ir = toIreal(toString(ireal.min)); | |
1181 assert(toString(ir) == toString(ireal.min)); | |
1182 assert(feq(cast(real)ir.re, cast(real)ireal.min.re)); | |
1183 assert(feq(cast(real)ir.im, cast(real)ireal.min.im)); | |
1184 | |
1185 ir = toIreal(toString(ireal.max)); | |
1186 assert(toString(ir) == toString(ireal.max)); | |
1187 assert(feq(cast(real)ir.re, cast(real)ireal.max.re)); | |
1188 //assert(feq(cast(real)ir.im, cast(real)ireal.max.im)); | |
1189 | |
1190 // nan | |
1191 ir = toIreal("nani"); | |
1192 assert(cast(real)ir == cast(real)ireal.nan); | |
1193 | |
1194 ir = toIreal(toString(ireal.nan)); | |
1195 assert(toString(ir) == toString(ireal.nan)); | |
1196 } | |
1197 | |
1198 | |
1199 /******************************************************* | |
1200 * ditto | |
1201 */ | |
1202 cfloat toCfloat(in char[] s) | |
1203 { | |
1204 char[] s1; | |
1205 char[] s2; | |
1206 real r1; | |
1207 real r2; | |
1208 cfloat cf; | |
1209 bool b = 0; | |
1210 char* endptr; | |
1211 | |
1212 if (!s.length) | |
1213 goto Lerr; | |
1214 | |
1215 b = getComplexStrings(s, s1, s2); | |
1216 | |
1217 if (!b) | |
1218 goto Lerr; | |
1219 | |
1220 // atof(s1); | |
1221 endptr = &s1[s1.length - 1]; | |
1222 r1 = strtold(s1, &endptr); | |
1223 | |
1224 // atof(s2); | |
1225 endptr = &s2[s2.length - 1]; | |
1226 r2 = strtold(s2, &endptr); | |
1227 | |
1228 cf = cast(cfloat)(r1 + (r2 * 1.0i)); | |
1229 | |
1230 //writefln( "toCfloat() r1=%g, r2=%g, cf=%g, max=%g", | |
1231 // r1, r2, cf, cfloat.max); | |
1232 // Currently disabled due to a posted bug where a | |
1233 // complex float greater-than compare to .max compares | |
1234 // incorrectly. | |
1235 //if (cf > cfloat.max) | |
1236 // goto Loverflow; | |
1237 | |
1238 return cf; | |
1239 | |
1240 Loverflow: | |
1241 conv_overflow(s); | |
1242 | |
1243 Lerr: | |
1244 conv_error(s); | |
1245 return cast(cfloat)0.0e-0+0i; | |
1246 } | |
1247 | |
1248 unittest | |
1249 { | |
1250 debug(conv) writefln("conv.toCfloat.unittest"); | |
1251 cfloat cf; | |
1252 | |
1253 cf = toCfloat(toString("1.2345e-5+0i")); | |
1254 assert(toString(cf) == toString(1.2345e-5+0i)); | |
1255 assert(feq(cf, 1.2345e-5+0i)); | |
1256 | |
1257 // min and max | |
1258 cf = toCfloat(toString(cfloat.min)); | |
1259 assert(toString(cf) == toString(cfloat.min)); | |
1260 | |
1261 cf = toCfloat(toString(cfloat.max)); | |
1262 assert(toString(cf) == toString(cfloat.max)); | |
1263 | |
1264 // nan ( nan+nani ) | |
1265 cf = toCfloat("nani"); | |
1266 //writefln("toCfloat() cf=%g, cf=\"%s\", nan=%s", | |
1267 // cf, toString(cf), toString(cfloat.nan)); | |
1268 assert(toString(cf) == toString(cfloat.nan)); | |
1269 | |
1270 cf = toCdouble("nan+nani"); | |
1271 assert(toString(cf) == toString(cfloat.nan)); | |
1272 | |
1273 cf = toCfloat(toString(cfloat.nan)); | |
1274 assert(toString(cf) == toString(cfloat.nan)); | |
1275 assert(feq(cast(creal)cf, cast(creal)cfloat.nan)); | |
1276 } | |
1277 | |
1278 /******************************************************* | |
1279 * ditto | |
1280 */ | |
1281 cdouble toCdouble(in char[] s) | |
1282 { | |
1283 char[] s1; | |
1284 char[] s2; | |
1285 real r1; | |
1286 real r2; | |
1287 cdouble cd; | |
1288 bool b = 0; | |
1289 char* endptr; | |
1290 | |
1291 if (!s.length) | |
1292 goto Lerr; | |
1293 | |
1294 b = getComplexStrings(s, s1, s2); | |
1295 | |
1296 if (!b) | |
1297 goto Lerr; | |
1298 | |
1299 // atof(s1); | |
1300 endptr = &s1[s1.length - 1]; | |
1301 r1 = strtold(s1, &endptr); | |
1302 | |
1303 // atof(s2); | |
1304 endptr = &s2[s2.length - 1]; | |
1305 r2 = strtold(s2, &endptr); //atof(s2); | |
1306 | |
1307 cd = cast(cdouble)(r1 + (r2 * 1.0i)); | |
1308 | |
1309 //Disabled, waiting on a bug fix. | |
1310 //if (cd > cdouble.max) //same problem the toCfloat() having | |
1311 // goto Loverflow; | |
1312 | |
1313 return cd; | |
1314 | |
1315 Loverflow: | |
1316 conv_overflow(s); | |
1317 | |
1318 Lerr: | |
1319 conv_error(s); | |
1320 return cast(cdouble)0.0e-0+0i; | |
1321 } | |
1322 | |
1323 unittest | |
1324 { | |
1325 debug(conv) writefln("conv.toCdouble.unittest"); | |
1326 cdouble cd; | |
1327 | |
1328 cd = toCdouble(toString("1.2345e-5+0i")); | |
1329 assert(toString( cd ) == toString(1.2345e-5+0i)); | |
1330 assert(feq(cd, 1.2345e-5+0i)); | |
1331 | |
1332 // min and max | |
1333 cd = toCdouble(toString(cdouble.min)); | |
1334 assert(toString(cd) == toString(cdouble.min)); | |
1335 assert(feq(cast(creal)cd, cast(creal)cdouble.min)); | |
1336 | |
1337 cd = toCdouble(toString(cdouble.max)); | |
1338 assert(toString( cd ) == toString(cdouble.max)); | |
1339 assert(feq(cast(creal)cd, cast(creal)cdouble.max)); | |
1340 | |
1341 // nan ( nan+nani ) | |
1342 cd = toCdouble("nani"); | |
1343 assert(toString(cd) == toString(cdouble.nan)); | |
1344 | |
1345 cd = toCdouble("nan+nani"); | |
1346 assert(toString(cd) == toString(cdouble.nan)); | |
1347 | |
1348 cd = toCdouble(toString(cdouble.nan)); | |
1349 assert(toString(cd) == toString(cdouble.nan)); | |
1350 assert(feq(cast(creal)cd, cast(creal)cdouble.nan)); | |
1351 } | |
1352 | |
1353 /******************************************************* | |
1354 * ditto | |
1355 */ | |
1356 creal toCreal(in char[] s) | |
1357 { | |
1358 char[] s1; | |
1359 char[] s2; | |
1360 real r1; | |
1361 real r2; | |
1362 creal cr; | |
1363 bool b = 0; | |
1364 char* endptr; | |
1365 | |
1366 if (!s.length) | |
1367 goto Lerr; | |
1368 | |
1369 b = getComplexStrings(s, s1, s2); | |
1370 | |
1371 if (!b) | |
1372 goto Lerr; | |
1373 | |
1374 // atof(s1); | |
1375 endptr = &s1[s1.length - 1]; | |
1376 r1 = strtold(s1, &endptr); | |
1377 | |
1378 // atof(s2); | |
1379 endptr = &s2[s2.length - 1]; | |
1380 r2 = strtold(s2, &endptr); //atof(s2); | |
1381 | |
1382 //writefln("toCreal() r1=%g, r2=%g, s1=\"%s\", s2=\"%s\", nan=%g", | |
1383 // r1, r2, s1, s2, creal.nan); | |
1384 | |
1385 if (s1 =="nan" && s2 == "nani") | |
1386 cr = creal.nan; | |
1387 else if (r2 != 0.0) | |
1388 cr = cast(creal)(r1 + (r2 * 1.0i)); | |
1389 else | |
1390 cr = cast(creal)(r1 + 0.0i); | |
1391 | |
1392 return cr; | |
1393 | |
1394 Lerr: | |
1395 conv_error(s); | |
1396 return cast(creal)0.0e-0+0i; | |
1397 } | |
1398 | |
1399 unittest | |
1400 { | |
1401 debug(conv) writefln("conv.toCreal.unittest"); | |
1402 creal cr; | |
1403 | |
1404 cr = toCreal(toString("1.2345e-5+0i")); | |
1405 assert(toString(cr) == toString(1.2345e-5+0i)); | |
1406 assert(feq(cr, 1.2345e-5+0i)); | |
1407 | |
1408 cr = toCreal(toString("0.0e-0+0i")); | |
1409 assert(toString(cr) == toString(0.0e-0+0i)); | |
1410 assert(cr == 0.0e-0+0i); | |
1411 assert(feq(cr, 0.0e-0+0i)); | |
1412 | |
1413 cr = toCreal("123"); | |
1414 assert(cr == 123); | |
1415 | |
1416 cr = toCreal("+5"); | |
1417 assert(cr == 5); | |
1418 | |
1419 cr = toCreal("-78"); | |
1420 assert(cr == -78); | |
1421 | |
1422 // min and max | |
1423 cr = toCreal(toString(creal.min)); | |
1424 assert(toString(cr) == toString(creal.min)); | |
1425 assert(feq(cr, creal.min)); | |
1426 | |
1427 cr = toCreal(toString(creal.max)); | |
1428 assert(toString(cr) == toString(creal.max)); | |
1429 assert(feq(cr, creal.max)); | |
1430 | |
1431 // nan ( nan+nani ) | |
1432 cr = toCreal("nani"); | |
1433 assert(toString(cr) == toString(creal.nan)); | |
1434 | |
1435 cr = toCreal("nan+nani"); | |
1436 assert(toString(cr) == toString(creal.nan)); | |
1437 | |
1438 cr = toCreal(toString(cdouble.nan)); | |
1439 assert(toString(cr) == toString(creal.nan)); | |
1440 assert(feq(cr, creal.nan)); | |
1441 } | |
1442 | |
1443 } | |
1444 | |
1445 /* ************************************************************** | |
1446 * Splits a complex float (cfloat, cdouble, and creal) into two workable strings. | |
1447 * Grammar: | |
1448 * ['+'|'-'] string floating-point digit {digit} | |
1449 */ | |
1450 private bool getComplexStrings(in char[] s, out char[] s1, out char[] s2) | |
1451 { | |
1452 int len = s.length; | |
1453 | |
1454 if (!len) | |
1455 goto Lerr; | |
1456 | |
1457 // When "nan" or "nani" just return them. | |
1458 if (s == "nan" || s == "nani" || s == "nan+nani") | |
1459 { | |
1460 s1 = "nan"; | |
1461 s2 = "nani"; | |
1462 return 1; | |
1463 } | |
1464 | |
1465 // Split the original string out into two strings. | |
1466 for (int i = 1; i < len; i++) | |
1467 if ((s[i - 1] != 'e' && s[i - 1] != 'E') && s[i] == '+') | |
1468 { | |
1469 s1 = s[0..i]; | |
1470 if (i + 1 < len - 1) | |
1471 s2 = s[i + 1..len - 1]; | |
1472 else | |
1473 s2 = "0e+0i"; | |
1474 | |
1475 break; | |
1476 } | |
1477 | |
1478 // Handle the case when there's only a single value | |
1479 // to work with, and set the other string to zero. | |
1480 if (!s1.length) | |
1481 { | |
1482 s1 = s; | |
1483 s2 = "0e+0i"; | |
1484 } | |
1485 | |
1486 //writefln( "getComplexStrings() s=\"%s\", s1=\"%s\", s2=\"%s\", len=%d", | |
1487 // s, s1, s2, len ); | |
1488 | |
1489 return 1; | |
1490 | |
1491 Lerr: | |
1492 // Display the original string in the error message. | |
1493 conv_error("getComplexStrings() \"" ~ s ~ "\"" ~ " s1=\"" ~ s1 ~ "\"" ~ " s2=\"" ~ s2 ~ "\""); | |
1494 return 0; | |
1495 } | |
1496 | |
1497 // feq() functions now used only in unittesting | |
1498 | |
1499 /* *************************************** | |
1500 * Main function to compare reals with given precision | |
1501 */ | |
1502 private bool feq(in real rx, in real ry, in real precision) | |
1503 { | |
1504 if (rx == ry) | |
1505 return 1; | |
1506 | |
1507 if (isnan(rx)) | |
1508 return cast(bool)isnan(ry); | |
1509 | |
1510 if (isnan(ry)) | |
1511 return 0; | |
1512 | |
1513 return cast(bool)(fabs(rx - ry) <= precision); | |
1514 } | |
1515 | |
1516 /* *************************************** | |
1517 * (Note: Copied here from std.math's mfeq() function for unittesting) | |
1518 * Simple function to compare two floating point values | |
1519 * to a specified precision. | |
1520 * Returns: | |
1521 * 1 match | |
1522 * 0 nomatch | |
1523 */ | |
1524 private bool feq(in real r1, in real r2) | |
1525 { | |
1526 if (r1 == r2) | |
1527 return 1; | |
1528 | |
1529 if (isnan(r1)) | |
1530 return cast(bool)isnan(r2); | |
1531 | |
1532 if (isnan(r2)) | |
1533 return 0; | |
1534 | |
1535 return cast(bool)(feq(r1, r2, 0.000001L)); | |
1536 } | |
1537 | |
1538 /* *************************************** | |
1539 * compare ireals with given precision | |
1540 */ | |
1541 private bool feq(in ireal r1, in ireal r2) | |
1542 { | |
1543 real rx = cast(real)r1; | |
1544 real ry = cast(real)r2; | |
1545 | |
1546 if (rx == ry) | |
1547 return 1; | |
1548 | |
1549 if (isnan(rx)) | |
1550 return cast(bool)isnan(ry); | |
1551 | |
1552 if (isnan(ry)) | |
1553 return 0; | |
1554 | |
1555 return feq(rx, ry, 0.000001L); | |
1556 } | |
1557 | |
1558 /* *************************************** | |
1559 * compare creals with given precision | |
1560 */ | |
1561 private bool feq(in creal r1, in creal r2) | |
1562 { | |
1563 real r1a = fabs(cast(real)r1.re - cast(real)r2.re); | |
1564 real r2b = fabs(cast(real)r1.im - cast(real)r2.im); | |
1565 | |
1566 if ((cast(real)r1.re == cast(real)r2.re) && | |
1567 (cast(real)r1.im == cast(real)r2.im)) | |
1568 return 1; | |
1569 | |
1570 if (isnan(r1a)) | |
1571 return cast(bool)isnan(r2b); | |
1572 | |
1573 if (isnan(r2b)) | |
1574 return 0; | |
1575 | |
1576 return feq(r1a, r2b, 0.000001L); | |
1577 } | |
1578 |