1 | /* Print floating point number in hexadecimal notation according to ISO C99. |
---|---|

2 | Copyright (C) 1997-2012 Free Software Foundation, Inc. |

3 | This file is part of the GNU C Library. |

4 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. |

5 | |

6 | The GNU C Library is free software; you can redistribute it and/or |

7 | modify it under the terms of the GNU Lesser General Public |

8 | License as published by the Free Software Foundation; either |

9 | version 2.1 of the License, or (at your option) any later version. |

10 | |

11 | The GNU C Library is distributed in the hope that it will be useful, |

12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |

13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |

14 | Lesser General Public License for more details. |

15 | |

16 | You should have received a copy of the GNU Lesser General Public |

17 | License along with the GNU C Library; if not, see |

18 | <http://www.gnu.org/licenses/>. */ |

19 | |

20 | #include <config.h> |

21 | #include <math.h> |

22 | #include <stdlib.h> |

23 | #include <stdio.h> |

24 | #include <string.h> |

25 | #include <stdbool.h> |

26 | #define NDEBUG |

27 | #include <assert.h> |

28 | #include "quadmath-rounding-mode.h" |

29 | #include "quadmath-printf.h" |

30 | #include "_itoa.h" |

31 | #include "_itowa.h" |

32 | |

33 | |

34 | /* Macros for doing the actual output. */ |

35 | |

36 | #define outchar(ch) \ |

37 | do \ |

38 | { \ |

39 | register const int outc = (ch); \ |

40 | if (PUTC (outc, fp) == EOF) \ |

41 | return -1; \ |

42 | ++done; \ |

43 | } while (0) |

44 | |

45 | #define PRINT(ptr, wptr, len) \ |

46 | do \ |

47 | { \ |

48 | register size_t outlen = (len); \ |

49 | if (wide) \ |

50 | while (outlen-- > 0) \ |

51 | outchar (*wptr++); \ |

52 | else \ |

53 | while (outlen-- > 0) \ |

54 | outchar (*ptr++); \ |

55 | } while (0) |

56 | |

57 | #define PADN(ch, len) \ |

58 | do \ |

59 | { \ |

60 | if (PAD (fp, ch, len) != len) \ |

61 | return -1; \ |

62 | done += len; \ |

63 | } \ |

64 | while (0) |

65 | |

66 | |

67 | |

68 | int |

69 | __quadmath_printf_fphex (struct __quadmath_printf_file *fp, |

70 | const struct printf_info *info, |

71 | const void *const *args) |

72 | { |

73 | /* The floating-point value to output. */ |

74 | ieee854_float128 fpnum; |

75 | |

76 | /* Locale-dependent representation of decimal point. */ |

77 | const char *decimal; |

78 | wchar_t decimalwc; |

79 | |

80 | /* "NaN" or "Inf" for the special cases. */ |

81 | const char *special = NULL; |

82 | const wchar_t *wspecial = NULL; |

83 | |

84 | /* Buffer for the generated number string for the mantissa. The |

85 | maximal size for the mantissa is 128 bits. */ |

86 | char numbuf[32]; |

87 | char *numstr; |

88 | char *numend; |

89 | wchar_t wnumbuf[32]; |

90 | wchar_t *wnumstr; |

91 | wchar_t *wnumend; |

92 | int negative; |

93 | |

94 | /* The maximal exponent of two in decimal notation has 5 digits. */ |

95 | char expbuf[5]; |

96 | char *expstr; |

97 | wchar_t wexpbuf[5]; |

98 | wchar_t *wexpstr; |

99 | int expnegative; |

100 | int exponent; |

101 | |

102 | /* Non-zero is mantissa is zero. */ |

103 | int zero_mantissa; |

104 | |

105 | /* The leading digit before the decimal point. */ |

106 | char leading; |

107 | |

108 | /* Precision. */ |

109 | int precision = info->prec; |

110 | |

111 | /* Width. */ |

112 | int width = info->width; |

113 | |

114 | /* Number of characters written. */ |

115 | int done = 0; |

116 | |

117 | /* Nonzero if this is output on a wide character stream. */ |

118 | int wide = info->wide; |

119 | |

120 | bool do_round_away; |

121 | |

122 | /* Figure out the decimal point character. */ |

123 | #ifdef USE_NL_LANGINFO |

124 | if (info->extra == 0) |

125 | decimal = nl_langinfo (DECIMAL_POINT); |

126 | else |

127 | { |

128 | decimal = nl_langinfo (MON_DECIMAL_POINT); |

129 | if (*decimal == '\0') |

130 | decimal = nl_langinfo (DECIMAL_POINT); |

131 | } |

132 | /* The decimal point character must never be zero. */ |

133 | assert (*decimal != '\0'); |

134 | #elif defined USE_LOCALECONV |

135 | const struct lconv *lc = localeconv (); |

136 | if (info->extra == 0) |

137 | decimal = lc->decimal_point; |

138 | else |

139 | { |

140 | decimal = lc->mon_decimal_point; |

141 | if (decimal == NULL || *decimal == '\0') |

142 | decimal = lc->decimal_point; |

143 | } |

144 | if (decimal == NULL || *decimal == '\0') |

145 | decimal = "."; |

146 | #else |

147 | decimal = "."; |

148 | #endif |

149 | #ifdef USE_NL_LANGINFO_WC |

150 | if (info->extra == 0) |

151 | decimalwc = nl_langinfo_wc (_NL_NUMERIC_DECIMAL_POINT_WC); |

152 | else |

153 | { |

154 | decimalwc = nl_langinfo_wc (_NL_MONETARY_DECIMAL_POINT_WC); |

155 | if (decimalwc == L_('\0')) |

156 | decimalwc = nl_langinfo_wc (_NL_NUMERIC_DECIMAL_POINT_WC); |

157 | } |

158 | /* The decimal point character must never be zero. */ |

159 | assert (decimalwc != L_('\0')); |

160 | #else |

161 | decimalwc = L_('.'); |

162 | #endif |

163 | |

164 | /* Fetch the argument value. */ |

165 | { |

166 | fpnum.value = **(const __float128 **) args[0]; |

167 | |

168 | /* Check for special values: not a number or infinity. */ |

169 | if (isnanq (fpnum.value)) |

170 | { |

171 | negative = fpnum.ieee.negative != 0; |

172 | if (isupper (info->spec)) |

173 | { |

174 | special = "NAN"; |

175 | wspecial = L_("NAN"); |

176 | } |

177 | else |

178 | { |

179 | special = "nan"; |

180 | wspecial = L_("nan"); |

181 | } |

182 | } |

183 | else |

184 | { |

185 | if (isinfq (fpnum.value)) |

186 | { |

187 | if (isupper (info->spec)) |

188 | { |

189 | special = "INF"; |

190 | wspecial = L_("INF"); |

191 | } |

192 | else |

193 | { |

194 | special = "inf"; |

195 | wspecial = L_("inf"); |

196 | } |

197 | } |

198 | |

199 | negative = signbitq (fpnum.value); |

200 | } |

201 | } |

202 | |

203 | if (special) |

204 | { |

205 | int width = info->width; |

206 | |

207 | if (negative || info->showsign || info->space) |

208 | --width; |

209 | width -= 3; |

210 | |

211 | if (!info->left && width > 0) |

212 | PADN (' ', width); |

213 | |

214 | if (negative) |

215 | outchar ('-'); |

216 | else if (info->showsign) |

217 | outchar ('+'); |

218 | else if (info->space) |

219 | outchar (' '); |

220 | |

221 | PRINT (special, wspecial, 3); |

222 | |

223 | if (info->left && width > 0) |

224 | PADN (' ', width); |

225 | |

226 | return done; |

227 | } |

228 | |

229 | { |

230 | /* We have 112 bits of mantissa plus one implicit digit. Since |

231 | 112 bits are representable without rest using hexadecimal |

232 | digits we use only the implicit digits for the number before |

233 | the decimal point. */ |

234 | uint64_t num0, num1; |

235 | |

236 | assert (sizeof (long double) == 16); |

237 | |

238 | num0 = fpnum.ieee.mant_high; |

239 | num1 = fpnum.ieee.mant_low; |

240 | |

241 | zero_mantissa = (num0|num1) == 0; |

242 | |

243 | if (sizeof (unsigned long int) > 6) |

244 | { |

245 | numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16, |

246 | info->spec == 'A'); |

247 | wnumstr = _itowa_word (num1, |

248 | wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), |

249 | 16, info->spec == 'A'); |

250 | } |

251 | else |

252 | { |

253 | numstr = _itoa (num1, numbuf + sizeof numbuf, 16, |

254 | info->spec == 'A'); |

255 | wnumstr = _itowa (num1, |

256 | wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t), |

257 | 16, info->spec == 'A'); |

258 | } |

259 | |

260 | while (numstr > numbuf + (sizeof numbuf - 64 / 4)) |

261 | { |

262 | *--numstr = '0'; |

263 | *--wnumstr = L_('0'); |

264 | } |

265 | |

266 | if (sizeof (unsigned long int) > 6) |

267 | { |

268 | numstr = _itoa_word (num0, numstr, 16, info->spec == 'A'); |

269 | wnumstr = _itowa_word (num0, wnumstr, 16, info->spec == 'A'); |

270 | } |

271 | else |

272 | { |

273 | numstr = _itoa (num0, numstr, 16, info->spec == 'A'); |

274 | wnumstr = _itowa (num0, wnumstr, 16, info->spec == 'A'); |

275 | } |

276 | |

277 | /* Fill with zeroes. */ |

278 | while (numstr > numbuf + (sizeof numbuf - 112 / 4)) |

279 | { |

280 | *--wnumstr = L_('0'); |

281 | *--numstr = '0'; |

282 | } |

283 | |

284 | leading = fpnum.ieee.exponent == 0 ? '0' : '1'; |

285 | |

286 | exponent = fpnum.ieee.exponent; |

287 | |

288 | if (exponent == 0) |

289 | { |

290 | if (zero_mantissa) |

291 | expnegative = 0; |

292 | else |

293 | { |

294 | /* This is a denormalized number. */ |

295 | expnegative = 1; |

296 | exponent = IEEE854_FLOAT128_BIAS - 1; |

297 | } |

298 | } |

299 | else if (exponent >= IEEE854_FLOAT128_BIAS) |

300 | { |

301 | expnegative = 0; |

302 | exponent -= IEEE854_FLOAT128_BIAS; |

303 | } |

304 | else |

305 | { |

306 | expnegative = 1; |

307 | exponent = -(exponent - IEEE854_FLOAT128_BIAS); |

308 | } |

309 | } |

310 | |

311 | /* Look for trailing zeroes. */ |

312 | if (! zero_mantissa) |

313 | { |

314 | wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]]; |

315 | numend = &numbuf[sizeof numbuf / sizeof numbuf[0]]; |

316 | while (wnumend[-1] == L_('0')) |

317 | { |

318 | --wnumend; |

319 | --numend; |

320 | } |

321 | |

322 | do_round_away = false; |

323 | |

324 | if (precision != -1 && precision < numend - numstr) |

325 | { |

326 | char last_digit = precision > 0 ? numstr[precision - 1] : leading; |

327 | char next_digit = numstr[precision]; |

328 | int last_digit_value = (last_digit >= 'A' && last_digit <= 'F' |

329 | ? last_digit - 'A' + 10 |

330 | : (last_digit >= 'a' && last_digit <= 'f' |

331 | ? last_digit - 'a' + 10 |

332 | : last_digit - '0')); |

333 | int next_digit_value = (next_digit >= 'A' && next_digit <= 'F' |

334 | ? next_digit - 'A' + 10 |

335 | : (next_digit >= 'a' && next_digit <= 'f' |

336 | ? next_digit - 'a' + 10 |

337 | : next_digit - '0')); |

338 | bool more_bits = ((next_digit_value & 7) != 0 |

339 | || precision + 1 < numend - numstr); |

340 | #ifdef HAVE_FENV_H |

341 | int rounding_mode = get_rounding_mode (); |

342 | do_round_away = round_away (negative, last_digit_value & 1, |

343 | next_digit_value >= 8, more_bits, |

344 | rounding_mode); |

345 | #endif |

346 | } |

347 | |

348 | if (precision == -1) |

349 | precision = numend - numstr; |

350 | else if (do_round_away) |

351 | { |

352 | /* Round up. */ |

353 | int cnt = precision; |

354 | while (--cnt >= 0) |

355 | { |

356 | char ch = numstr[cnt]; |

357 | /* We assume that the digits and the letters are ordered |

358 | like in ASCII. This is true for the rest of GNU, too. */ |

359 | if (ch == '9') |

360 | { |

361 | wnumstr[cnt] = (wchar_t) info->spec; |

362 | numstr[cnt] = info->spec; /* This is tricky, |

363 | think about it! */ |

364 | break; |

365 | } |

366 | else if (tolower (ch) < 'f') |

367 | { |

368 | ++numstr[cnt]; |

369 | ++wnumstr[cnt]; |

370 | break; |

371 | } |

372 | else |

373 | { |

374 | numstr[cnt] = '0'; |

375 | wnumstr[cnt] = L_('0'); |

376 | } |

377 | } |

378 | if (cnt < 0) |

379 | { |

380 | /* The mantissa so far was fff...f Now increment the |

381 | leading digit. Here it is again possible that we |

382 | get an overflow. */ |

383 | if (leading == '9') |

384 | leading = info->spec; |

385 | else if (tolower (leading) < 'f') |

386 | ++leading; |

387 | else |

388 | { |

389 | leading = '1'; |

390 | if (expnegative) |

391 | { |

392 | exponent -= 4; |

393 | if (exponent <= 0) |

394 | { |

395 | exponent = -exponent; |

396 | expnegative = 0; |

397 | } |

398 | } |

399 | else |

400 | exponent += 4; |

401 | } |

402 | } |

403 | } |

404 | } |

405 | else |

406 | { |

407 | if (precision == -1) |

408 | precision = 0; |

409 | numend = numstr; |

410 | wnumend = wnumstr; |

411 | } |

412 | |

413 | /* Now we can compute the exponent string. */ |

414 | expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0); |

415 | wexpstr = _itowa_word (exponent, |

416 | wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0); |

417 | |

418 | /* Now we have all information to compute the size. */ |

419 | width -= ((negative || info->showsign || info->space) |

420 | /* Sign. */ |

421 | + 2 + 1 + 0 + precision + 1 + 1 |

422 | /* 0x h . hhh P ExpoSign. */ |

423 | + ((expbuf + sizeof expbuf) - expstr)); |

424 | /* Exponent. */ |

425 | |

426 | /* Count the decimal point. |

427 | A special case when the mantissa or the precision is zero and the `#' |

428 | is not given. In this case we must not print the decimal point. */ |

429 | if (precision > 0 || info->alt) |

430 | width -= wide ? 1 : strlen (decimal); |

431 | |

432 | if (!info->left && info->pad != '0' && width > 0) |

433 | PADN (' ', width); |

434 | |

435 | if (negative) |

436 | outchar ('-'); |

437 | else if (info->showsign) |

438 | outchar ('+'); |

439 | else if (info->space) |

440 | outchar (' '); |

441 | |

442 | outchar ('0'); |

443 | if ('X' - 'A' == 'x' - 'a') |

444 | outchar (info->spec + ('x' - 'a')); |

445 | else |

446 | outchar (info->spec == 'A' ? 'X' : 'x'); |

447 | |

448 | if (!info->left && info->pad == '0' && width > 0) |

449 | PADN ('0', width); |

450 | |

451 | outchar (leading); |

452 | |

453 | if (precision > 0 || info->alt) |

454 | { |

455 | const wchar_t *wtmp = &decimalwc; |

456 | PRINT (decimal, wtmp, wide ? 1 : strlen (decimal)); |

457 | } |

458 | |

459 | if (precision > 0) |

460 | { |

461 | ssize_t tofill = precision - (numend - numstr); |

462 | PRINT (numstr, wnumstr, MIN (numend - numstr, precision)); |

463 | if (tofill > 0) |

464 | PADN ('0', tofill); |

465 | } |

466 | |

467 | if ('P' - 'A' == 'p' - 'a') |

468 | outchar (info->spec + ('p' - 'a')); |

469 | else |

470 | outchar (info->spec == 'A' ? 'P' : 'p'); |

471 | |

472 | outchar (expnegative ? '-' : '+'); |

473 | |

474 | PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr); |

475 | |

476 | if (info->left && info->pad != '0' && width > 0) |

477 | PADN (info->pad, width); |

478 | |

479 | return done; |

480 | } |

481 |