131
|
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
|