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