re PR fortran/37834 (write(*,'(f0.0)') 0.0 prints "." instead of "0.")
[gcc.git] / libgfortran / io / write_float.def
1 /* Copyright (C) 2007, 2008 Free Software Foundation, Inc.
2 Contributed by Andy Vaught
3 Write float code factoring to this file by Jerry DeLisle
4 F2003 I/O support contributed by Jerry DeLisle
5
6 This file is part of the GNU Fortran 95 runtime library (libgfortran).
7
8 Libgfortran is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 In addition to the permissions in the GNU General Public License, the
14 Free Software Foundation gives you unlimited permission to link the
15 compiled version of this file into combinations with other programs,
16 and to distribute those combinations without any restriction coming
17 from the use of this file. (The General Public License restrictions
18 do apply in other respects; for example, they cover modification of
19 the file, and distribution when not linked into a combine
20 executable.)
21
22 Libgfortran is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with Libgfortran; see the file COPYING. If not, write to
29 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
30 Boston, MA 02110-1301, USA. */
31
32 #include "config.h"
33
34 typedef enum
35 { S_NONE, S_MINUS, S_PLUS }
36 sign_t;
37
38 /* Given a flag that indicates if a value is negative or not, return a
39 sign_t that gives the sign that we need to produce. */
40
41 static sign_t
42 calculate_sign (st_parameter_dt *dtp, int negative_flag)
43 {
44 sign_t s = S_NONE;
45
46 if (negative_flag)
47 s = S_MINUS;
48 else
49 switch (dtp->u.p.sign_status)
50 {
51 case SIGN_SP: /* Show sign. */
52 s = S_PLUS;
53 break;
54 case SIGN_SS: /* Suppress sign. */
55 s = S_NONE;
56 break;
57 case SIGN_S: /* Processor defined. */
58 case SIGN_UNSPECIFIED:
59 s = options.optional_plus ? S_PLUS : S_NONE;
60 break;
61 }
62
63 return s;
64 }
65
66
67 /* Output a real number according to its format which is FMT_G free. */
68
69 static void
70 output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
71 int sign_bit, bool zero_flag, int ndigits, int edigits)
72 {
73 char *out;
74 char *digits;
75 int e;
76 char expchar;
77 format_token ft;
78 int w;
79 int d;
80 /* Number of digits before the decimal point. */
81 int nbefore;
82 /* Number of zeros after the decimal point. */
83 int nzero;
84 /* Number of digits after the decimal point. */
85 int nafter;
86 /* Number of zeros after the decimal point, whatever the precision. */
87 int nzero_real;
88 int leadzero;
89 int nblanks;
90 int i;
91 sign_t sign;
92
93 ft = f->format;
94 w = f->u.real.w;
95 d = f->u.real.d;
96
97 nzero_real = -1;
98
99 /* We should always know the field width and precision. */
100 if (d < 0)
101 internal_error (&dtp->common, "Unspecified precision");
102
103 sign = calculate_sign (dtp, sign_bit);
104
105 /* The following code checks the given string has punctuation in the correct
106 places. Uncomment if needed for debugging.
107 if (d != 0 && ((buffer[2] != '.' && buffer[2] != ',')
108 || buffer[ndigits + 2] != 'e'))
109 internal_error (&dtp->common, "printf is broken"); */
110
111 /* Read the exponent back in. */
112 e = atoi (&buffer[ndigits + 3]) + 1;
113
114 /* Make sure zero comes out as 0.0e0. */
115 if (zero_flag)
116 {
117 e = 0;
118 if (compile_options.sign_zero == 1)
119 sign = calculate_sign (dtp, sign_bit);
120 else
121 sign = calculate_sign (dtp, 0);
122
123 /* Handle special cases. */
124 if (w == 0)
125 w = 2;
126
127 /* For this one we choose to not output a decimal point.
128 F95 10.5.1.2.1 */
129 if (w == 1 && ft == FMT_F)
130 {
131 out = write_block (dtp, w);
132 if (out == NULL)
133 return;
134 *out = '0';
135 return;
136 }
137
138 }
139
140 /* Normalize the fractional component. */
141 buffer[2] = buffer[1];
142 digits = &buffer[2];
143
144 /* Figure out where to place the decimal point. */
145 switch (ft)
146 {
147 case FMT_F:
148 nbefore = e + dtp->u.p.scale_factor;
149 if (nbefore < 0)
150 {
151 nzero = -nbefore;
152 nzero_real = nzero;
153 if (nzero > d)
154 nzero = d;
155 nafter = d - nzero;
156 nbefore = 0;
157 }
158 else
159 {
160 nzero = 0;
161 nafter = d;
162 }
163 expchar = 0;
164 break;
165
166 case FMT_E:
167 case FMT_D:
168 i = dtp->u.p.scale_factor;
169 if (d <= 0 && i == 0)
170 {
171 generate_error (&dtp->common, LIBERROR_FORMAT, "Precision not "
172 "greater than zero in format specifier 'E' or 'D'");
173 return;
174 }
175 if (i <= -d || i >= d + 2)
176 {
177 generate_error (&dtp->common, LIBERROR_FORMAT, "Scale factor "
178 "out of range in format specifier 'E' or 'D'");
179 return;
180 }
181
182 if (!zero_flag)
183 e -= i;
184 if (i < 0)
185 {
186 nbefore = 0;
187 nzero = -i;
188 nafter = d + i;
189 }
190 else if (i > 0)
191 {
192 nbefore = i;
193 nzero = 0;
194 nafter = (d - i) + 1;
195 }
196 else /* i == 0 */
197 {
198 nbefore = 0;
199 nzero = 0;
200 nafter = d;
201 }
202
203 if (ft == FMT_E)
204 expchar = 'E';
205 else
206 expchar = 'D';
207 break;
208
209 case FMT_EN:
210 /* The exponent must be a multiple of three, with 1-3 digits before
211 the decimal point. */
212 if (!zero_flag)
213 e--;
214 if (e >= 0)
215 nbefore = e % 3;
216 else
217 {
218 nbefore = (-e) % 3;
219 if (nbefore != 0)
220 nbefore = 3 - nbefore;
221 }
222 e -= nbefore;
223 nbefore++;
224 nzero = 0;
225 nafter = d;
226 expchar = 'E';
227 break;
228
229 case FMT_ES:
230 if (!zero_flag)
231 e--;
232 nbefore = 1;
233 nzero = 0;
234 nafter = d;
235 expchar = 'E';
236 break;
237
238 default:
239 /* Should never happen. */
240 internal_error (&dtp->common, "Unexpected format token");
241 }
242
243 /* Round the value. */
244 if (nbefore + nafter == 0)
245 {
246 ndigits = 0;
247 if (nzero_real == d && digits[0] >= '5')
248 {
249 /* We rounded to zero but shouldn't have */
250 nzero--;
251 nafter = 1;
252 digits[0] = '1';
253 ndigits = 1;
254 }
255 }
256 else if (nbefore + nafter < ndigits)
257 {
258 ndigits = nbefore + nafter;
259 i = ndigits;
260 if (digits[i] >= '5')
261 {
262 /* Propagate the carry. */
263 for (i--; i >= 0; i--)
264 {
265 if (digits[i] != '9')
266 {
267 digits[i]++;
268 break;
269 }
270 digits[i] = '0';
271 }
272
273 if (i < 0)
274 {
275 /* The carry overflowed. Fortunately we have some spare space
276 at the start of the buffer. We may discard some digits, but
277 this is ok because we already know they are zero. */
278 digits--;
279 digits[0] = '1';
280 if (ft == FMT_F)
281 {
282 if (nzero > 0)
283 {
284 nzero--;
285 nafter++;
286 }
287 else
288 nbefore++;
289 }
290 else if (ft == FMT_EN)
291 {
292 nbefore++;
293 if (nbefore == 4)
294 {
295 nbefore = 1;
296 e += 3;
297 }
298 }
299 else
300 e++;
301 }
302 }
303 }
304
305 /* Calculate the format of the exponent field. */
306 if (expchar)
307 {
308 edigits = 1;
309 for (i = abs (e); i >= 10; i /= 10)
310 edigits++;
311
312 if (f->u.real.e < 0)
313 {
314 /* Width not specified. Must be no more than 3 digits. */
315 if (e > 999 || e < -999)
316 edigits = -1;
317 else
318 {
319 edigits = 4;
320 if (e > 99 || e < -99)
321 expchar = ' ';
322 }
323 }
324 else
325 {
326 /* Exponent width specified, check it is wide enough. */
327 if (edigits > f->u.real.e)
328 edigits = -1;
329 else
330 edigits = f->u.real.e + 2;
331 }
332 }
333 else
334 edigits = 0;
335
336 /* Pick a field size if none was specified. */
337 if (w <= 0)
338 w = nbefore + nzero + nafter + (sign != S_NONE ? 2 : 1);
339
340 /* Create the ouput buffer. */
341 out = write_block (dtp, w);
342 if (out == NULL)
343 return;
344
345 /* Zero values always output as positive, even if the value was negative
346 before rounding. */
347 for (i = 0; i < ndigits; i++)
348 {
349 if (digits[i] != '0')
350 break;
351 }
352 if (i == ndigits)
353 {
354 /* The output is zero, so set the sign according to the sign bit unless
355 -fno-sign-zero was specified. */
356 if (compile_options.sign_zero == 1)
357 sign = calculate_sign (dtp, sign_bit);
358 else
359 sign = calculate_sign (dtp, 0);
360 }
361
362 /* Work out how much padding is needed. */
363 nblanks = w - (nbefore + nzero + nafter + edigits + 1);
364 if (sign != S_NONE)
365 nblanks--;
366
367 /* Check the value fits in the specified field width. */
368 if (nblanks < 0 || edigits == -1)
369 {
370 star_fill (out, w);
371 return;
372 }
373
374 /* See if we have space for a zero before the decimal point. */
375 if (nbefore == 0 && nblanks > 0)
376 {
377 leadzero = 1;
378 nblanks--;
379 }
380 else
381 leadzero = 0;
382
383 /* Pad to full field width. */
384
385 if ( ( nblanks > 0 ) && !dtp->u.p.no_leading_blank)
386 {
387 memset (out, ' ', nblanks);
388 out += nblanks;
389 }
390
391 /* Output the initial sign (if any). */
392 if (sign == S_PLUS)
393 *(out++) = '+';
394 else if (sign == S_MINUS)
395 *(out++) = '-';
396
397 /* Output an optional leading zero. */
398 if (leadzero)
399 *(out++) = '0';
400
401 /* Output the part before the decimal point, padding with zeros. */
402 if (nbefore > 0)
403 {
404 if (nbefore > ndigits)
405 {
406 i = ndigits;
407 memcpy (out, digits, i);
408 ndigits = 0;
409 while (i < nbefore)
410 out[i++] = '0';
411 }
412 else
413 {
414 i = nbefore;
415 memcpy (out, digits, i);
416 ndigits -= i;
417 }
418
419 digits += i;
420 out += nbefore;
421 }
422 /* Output the decimal point. */
423 *(out++) = dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? '.' : ',';
424
425 /* Output leading zeros after the decimal point. */
426 if (nzero > 0)
427 {
428 for (i = 0; i < nzero; i++)
429 *(out++) = '0';
430 }
431
432 /* Output digits after the decimal point, padding with zeros. */
433 if (nafter > 0)
434 {
435 if (nafter > ndigits)
436 i = ndigits;
437 else
438 i = nafter;
439
440 memcpy (out, digits, i);
441 while (i < nafter)
442 out[i++] = '0';
443
444 digits += i;
445 ndigits -= i;
446 out += nafter;
447 }
448
449 /* Output the exponent. */
450 if (expchar)
451 {
452 if (expchar != ' ')
453 {
454 *(out++) = expchar;
455 edigits--;
456 }
457 #if HAVE_SNPRINTF
458 snprintf (buffer, size, "%+0*d", edigits, e);
459 #else
460 sprintf (buffer, "%+0*d", edigits, e);
461 #endif
462 memcpy (out, buffer, edigits);
463 }
464 if (dtp->u.p.no_leading_blank)
465 {
466 out += edigits;
467 memset( out , ' ' , nblanks );
468 dtp->u.p.no_leading_blank = 0;
469 }
470 #undef STR
471 #undef STR1
472 #undef MIN_FIELD_WIDTH
473 }
474
475
476 /* Write "Infinite" or "Nan" as appropriate for the given format. */
477
478 static void
479 write_infnan (st_parameter_dt *dtp, const fnode *f, int isnan_flag, int sign_bit)
480 {
481 char * p, fin;
482 int nb = 0;
483
484 if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z)
485 {
486 nb = f->u.real.w;
487
488 /* If the field width is zero, the processor must select a width
489 not zero. 4 is chosen to allow output of '-Inf' or '+Inf' */
490
491 if (nb == 0) nb = 4;
492 p = write_block (dtp, nb);
493 if (p == NULL)
494 return;
495 if (nb < 3)
496 {
497 memset (p, '*',nb);
498 return;
499 }
500
501 memset(p, ' ', nb);
502 if (!isnan_flag)
503 {
504 if (sign_bit)
505 {
506
507 /* If the sign is negative and the width is 3, there is
508 insufficient room to output '-Inf', so output asterisks */
509
510 if (nb == 3)
511 {
512 memset (p, '*',nb);
513 return;
514 }
515
516 /* The negative sign is mandatory */
517
518 fin = '-';
519 }
520 else
521
522 /* The positive sign is optional, but we output it for
523 consistency */
524 fin = '+';
525
526 if (nb > 8)
527
528 /* We have room, so output 'Infinity' */
529 memcpy(p + nb - 8, "Infinity", 8);
530 else
531
532 /* For the case of width equals 8, there is not enough room
533 for the sign and 'Infinity' so we go with 'Inf' */
534 memcpy(p + nb - 3, "Inf", 3);
535
536 if (nb < 9 && nb > 3)
537 p[nb - 4] = fin; /* Put the sign in front of Inf */
538 else if (nb > 8)
539 p[nb - 9] = fin; /* Put the sign in front of Infinity */
540 }
541 else
542 memcpy(p + nb - 3, "NaN", 3);
543 return;
544 }
545 }
546
547
548 /* Returns the value of 10**d. */
549
550 #define CALCULATE_EXP(x) \
551 inline static GFC_REAL_ ## x \
552 calculate_exp_ ## x (int d)\
553 {\
554 int i;\
555 GFC_REAL_ ## x r = 1.0;\
556 for (i = 0; i< (d >= 0 ? d : -d); i++)\
557 r *= 10;\
558 r = (d >= 0) ? r : 1.0 / r;\
559 return r;\
560 }
561
562 CALCULATE_EXP(4)
563
564 CALCULATE_EXP(8)
565
566 #ifdef HAVE_GFC_REAL_10
567 CALCULATE_EXP(10)
568 #endif
569
570 #ifdef HAVE_GFC_REAL_16
571 CALCULATE_EXP(16)
572 #endif
573 #undef CALCULATE_EXP
574
575 /* Generate corresponding I/O format for FMT_G and output.
576 The rules to translate FMT_G to FMT_E or FMT_F from DEC fortran
577 LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is:
578
579 Data Magnitude Equivalent Conversion
580 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee]
581 m = 0 F(w-n).(d-1), n' '
582 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' '
583 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' '
584 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' '
585 ................ ..........
586 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ')
587 m >= 10**d-0.5 Ew.d[Ee]
588
589 notes: for Gw.d , n' ' means 4 blanks
590 for Gw.dEe, n' ' means e+2 blanks */
591
592 #define OUTPUT_FLOAT_FMT_G(x) \
593 static void \
594 output_float_FMT_G_ ## x (st_parameter_dt *dtp, const fnode *f, \
595 GFC_REAL_ ## x m, char *buffer, size_t size, \
596 int sign_bit, bool zero_flag, int ndigits, int edigits) \
597 { \
598 int e = f->u.real.e;\
599 int d = f->u.real.d;\
600 int w = f->u.real.w;\
601 fnode *newf;\
602 GFC_REAL_ ## x exp_d;\
603 int low, high, mid;\
604 int ubound, lbound;\
605 char *p;\
606 int save_scale_factor, nb = 0;\
607 \
608 save_scale_factor = dtp->u.p.scale_factor;\
609 newf = get_mem (sizeof (fnode));\
610 \
611 exp_d = calculate_exp_ ## x (d);\
612 if ((m > 0.0 && m < 0.1 - 0.05 / exp_d) || (m >= exp_d - 0.5 ) ||\
613 ((m == 0.0) && !(compile_options.allow_std & GFC_STD_F2003)))\
614 { \
615 newf->format = FMT_E;\
616 newf->u.real.w = w;\
617 newf->u.real.d = d;\
618 newf->u.real.e = e;\
619 nb = 0;\
620 goto finish;\
621 }\
622 \
623 mid = 0;\
624 low = 0;\
625 high = d + 1;\
626 lbound = 0;\
627 ubound = d + 1;\
628 \
629 while (low <= high)\
630 { \
631 GFC_REAL_ ## x temp;\
632 mid = (low + high) / 2;\
633 \
634 temp = 0.1 * calculate_exp_ ## x (mid) - 0.5\
635 * calculate_exp_ ## x (mid - d - 1);\
636 \
637 if (m < temp)\
638 { \
639 ubound = mid;\
640 if (ubound == lbound + 1)\
641 break;\
642 high = mid - 1;\
643 }\
644 else if (m > temp)\
645 { \
646 lbound = mid;\
647 if (ubound == lbound + 1)\
648 { \
649 mid ++;\
650 break;\
651 }\
652 low = mid + 1;\
653 }\
654 else\
655 break;\
656 }\
657 \
658 if (e < 0)\
659 nb = 4;\
660 else\
661 nb = e + 2;\
662 \
663 newf->format = FMT_F;\
664 newf->u.real.w = f->u.real.w - nb;\
665 \
666 if (m == 0.0)\
667 newf->u.real.d = d - 1;\
668 else\
669 newf->u.real.d = - (mid - d - 1);\
670 \
671 dtp->u.p.scale_factor = 0;\
672 \
673 finish:\
674 output_float (dtp, newf, buffer, size, sign_bit, zero_flag, ndigits, \
675 edigits);\
676 dtp->u.p.scale_factor = save_scale_factor;\
677 \
678 free_mem(newf);\
679 \
680 if (nb > 0)\
681 { \
682 p = write_block (dtp, nb);\
683 if (p == NULL)\
684 return;\
685 memset (p, ' ', nb);\
686 }\
687 }\
688
689 OUTPUT_FLOAT_FMT_G(4)
690
691 OUTPUT_FLOAT_FMT_G(8)
692
693 #ifdef HAVE_GFC_REAL_10
694 OUTPUT_FLOAT_FMT_G(10)
695 #endif
696
697 #ifdef HAVE_GFC_REAL_16
698 OUTPUT_FLOAT_FMT_G(16)
699 #endif
700
701 #undef OUTPUT_FLOAT_FMT_G
702
703
704 /* Define a macro to build code for write_float. */
705
706 /* Note: Before output_float is called, sprintf is used to print to buffer the
707 number in the format +D.DDDDe+ddd. For an N digit exponent, this gives us
708 (MIN_FIELD_WIDTH-5)-N digits after the decimal point, plus another one
709 before the decimal point.
710
711 # The result will always contain a decimal point, even if no
712 digits follow it
713
714 - The converted value is to be left adjusted on the field boundary
715
716 + A sign (+ or -) always be placed before a number
717
718 MIN_FIELD_WIDTH minimum field width
719
720 * (ndigits-1) is used as the precision
721
722 e format: [-]d.ddde±dd where there is one digit before the
723 decimal-point character and the number of digits after it is
724 equal to the precision. The exponent always contains at least two
725 digits; if the value is zero, the exponent is 00. */
726
727 #ifdef HAVE_SNPRINTF
728
729 #define DTOA \
730 snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
731 "e", ndigits - 1, tmp);
732
733 #define DTOAL \
734 snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
735 "Le", ndigits - 1, tmp);
736
737 #else
738
739 #define DTOA \
740 sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
741 "e", ndigits - 1, tmp);
742
743 #define DTOAL \
744 sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
745 "Le", ndigits - 1, tmp);
746
747 #endif
748
749 #define WRITE_FLOAT(x,y)\
750 {\
751 GFC_REAL_ ## x tmp;\
752 tmp = * (GFC_REAL_ ## x *)source;\
753 sign_bit = signbit (tmp);\
754 if (!isfinite (tmp))\
755 { \
756 write_infnan (dtp, f, isnan (tmp), sign_bit);\
757 return;\
758 }\
759 tmp = sign_bit ? -tmp : tmp;\
760 if (f->u.real.d == 0 && f->format == FMT_F)\
761 {\
762 if (tmp < 0.5)\
763 tmp = 0.0;\
764 else if (tmp < 1.0)\
765 tmp = 1.0;\
766 }\
767 zero_flag = (tmp == 0.0);\
768 \
769 DTOA ## y\
770 \
771 if (f->format != FMT_G)\
772 output_float (dtp, f, buffer, size, sign_bit, zero_flag, ndigits, \
773 edigits);\
774 else \
775 output_float_FMT_G_ ## x (dtp, f, tmp, buffer, size, sign_bit, \
776 zero_flag, ndigits, edigits);\
777 }\
778
779 /* Output a real number according to its format. */
780
781 static void
782 write_float (st_parameter_dt *dtp, const fnode *f, const char *source, int len)
783 {
784
785 #if defined(HAVE_GFC_REAL_16) && __LDBL_DIG__ > 18
786 # define MIN_FIELD_WIDTH 46
787 #else
788 # define MIN_FIELD_WIDTH 31
789 #endif
790 #define STR(x) STR1(x)
791 #define STR1(x) #x
792
793 /* This must be large enough to accurately hold any value. */
794 char buffer[MIN_FIELD_WIDTH+1];
795 int sign_bit, ndigits, edigits;
796 bool zero_flag;
797 size_t size;
798
799 size = MIN_FIELD_WIDTH+1;
800
801 /* printf pads blanks for us on the exponent so we just need it big enough
802 to handle the largest number of exponent digits expected. */
803 edigits=4;
804
805 if (f->format == FMT_F || f->format == FMT_EN || f->format == FMT_G
806 || ((f->format == FMT_D || f->format == FMT_E)
807 && dtp->u.p.scale_factor != 0))
808 {
809 /* Always convert at full precision to avoid double rounding. */
810 ndigits = MIN_FIELD_WIDTH - 4 - edigits;
811 }
812 else
813 {
814 /* The number of digits is known, so let printf do the rounding. */
815 if (f->format == FMT_ES)
816 ndigits = f->u.real.d + 1;
817 else
818 ndigits = f->u.real.d;
819 if (ndigits > MIN_FIELD_WIDTH - 4 - edigits)
820 ndigits = MIN_FIELD_WIDTH - 4 - edigits;
821 }
822
823 switch (len)
824 {
825 case 4:
826 WRITE_FLOAT(4,)
827 break;
828
829 case 8:
830 WRITE_FLOAT(8,)
831 break;
832
833 #ifdef HAVE_GFC_REAL_10
834 case 10:
835 WRITE_FLOAT(10,L)
836 break;
837 #endif
838 #ifdef HAVE_GFC_REAL_16
839 case 16:
840 WRITE_FLOAT(16,L)
841 break;
842 #endif
843 default:
844 internal_error (NULL, "bad real kind");
845 }
846 }