ReactOS 0.4.16-dev-852-gcfcc8d8
_fptostr.cpp
Go to the documentation of this file.
1//
2// _fptostr.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines the internal function that writes a mantissa (in a STRFLT) into a
7// buffer. This function puts all of the digits into the buffer, handles
8// rounding based on the requested precision (digits), and updates the decimal
9// point position in the STRFLT object. Note that this function does not change
10// the mantissa field of the STRFLT, so callers of this function may rely on it
11// being unmodified.
12//
13#include <corecrt_internal.h>
16#include <fenv.h>
17#include <string.h>
18#include <stddef.h>
19
20// __acrt_has_trailing_digits::no_trailing isn't indicative of how to round if we're rounding to a point before the end of the generated digits.
21// __acrt_has_trailing_digits::no_trailing only says if there are any digits after the mantisa we got.
22// We need to ensure the remaining generated digits are all zero before choosing rounds-to-even behavior intended for exactly representable floating point numbers.
23static bool check_trailing(char const * mantissa_it, __acrt_has_trailing_digits const trailing_digits)
24{
25 if (trailing_digits == __acrt_has_trailing_digits::trailing)
26 {
27 return true;
28 }
29
30 while (*mantissa_it == '0')
31 {
32 mantissa_it++;
33 }
34
35 if (*mantissa_it != '\0')
36 {
37 return true;
38 }
39
40 return false;
41}
42
43static bool should_round_up(
44 char const * const mantissa_base,
45 char const * const mantissa_it,
46 int const sign,
47 __acrt_has_trailing_digits const trailing_digits,
49)
50{
52 {
53 return *mantissa_it >= '5';
54 }
55
56 int const round_mode = fegetround();
57
58 if (round_mode == FE_TONEAREST)
59 {
60 if (*mantissa_it > '5')
61 {
62 return true;
63 }
64
65 if (*mantissa_it < '5')
66 {
67 return false;
68 }
69
70 // If there are trailing digits we are in a scenario like this .5000000001 and should round up
71 if (check_trailing(mantissa_it + 1, trailing_digits))
72 {
73 return true;
74 }
75
76 // At this point, the number is exactly representable and we are rounding 5.
77 // In this case, IEEE 754 states to round towards the nearest even number.
78 // Therefore: if the previous digit is odd, we round up (1.5 -> 2).
79 // if the previous digit is even, we round down (2.5 -> 2).
80
81 // If there is no preceding digit, it is considered zero, so round down.
82 if (mantissa_it == mantissa_base)
83 {
84 return false;
85 }
86
87 // If the previous digit is odd, we should round up to the closest even.
88 return *(mantissa_it - 1) % 2;
89 }
90
91 if (round_mode == FE_UPWARD)
92 {
93 return check_trailing(mantissa_it, trailing_digits) && sign != '-';
94 }
95
96 if (round_mode == FE_DOWNWARD)
97 {
98 return check_trailing(mantissa_it, trailing_digits) && sign == '-';
99 }
100
101 return false;
102}
103
105 char* const buffer,
106 size_t const buffer_count,
107 int digits,
108 STRFLT const pflt,
109 __acrt_has_trailing_digits const trailing_digits,
111 __crt_cached_ptd_host& ptd
112)
113{
116 buffer[0] = '\0';
117
118 _UCRT_VALIDATE_RETURN_ERRCODE(ptd, buffer_count > static_cast<size_t>((digits > 0 ? digits : 0) + 1), ERANGE);
120
121 char* buffer_it = buffer;
122 char* const mantissa_base = pflt->mantissa;
123 char* mantissa_it = pflt->mantissa;
124
125 // The buffer will contain 'digits' decimal digits plus an optional overflow
126 // digit for the rounding.
127
128 // Initialize the first digit in the buffer to '0' (Note: not '\0') and set
129 // the pointer to the second digit of the buffer. The first digit is used
130 // to handle overflow on rounding (e.g. 9.999... becomes 10.000...), which
131 // requires a carry into the first digit.
132 *buffer_it++ = '0';
133
134 // Copy the digits of the value into the buffer (with '0' padding) and
135 // insert the null terminator:
136 while (digits > 0)
137 {
138 *buffer_it++ = *mantissa_it ? *mantissa_it++ : '0';
139 --digits;
140 }
141
142 *buffer_it = '\0';
143
144 // Do any rounding which may be needed. Note: if digits < 0, we don't do
145 // any rounding because in this case, the rounding occurs in a digit which
146 // will not be output because of the precision requested.
147 if (digits >= 0 && should_round_up(mantissa_base, mantissa_it, pflt->sign, trailing_digits, rounding_mode))
148 {
149 buffer_it--;
150
151 while (*buffer_it == '9')
152 {
153 *buffer_it-- = '0';
154 }
155
156 *buffer_it += 1;
157 }
158
159 if (*buffer == '1')
160 {
161 // The rounding caused overflow into the leading digit (e.g. 9.999...
162 // became 10.000...), so increment the decimal point position by 1:
163 pflt->decpt++;
164 }
165 else
166 {
167 // Move the entire string to the left one digit to remove the unused
168 // overflow digit:
169 memmove(buffer, buffer + 1, strlen(buffer + 1) + 1);
170 }
171
172 return 0;
173}
static bool check_trailing(char const *mantissa_it, __acrt_has_trailing_digits const trailing_digits)
Definition: _fptostr.cpp:23
errno_t __cdecl __acrt_fp_strflt_to_string(char *const buffer, size_t const buffer_count, int digits, STRFLT const pflt, __acrt_has_trailing_digits const trailing_digits, __acrt_rounding_mode const rounding_mode, __crt_cached_ptd_host &ptd)
Definition: _fptostr.cpp:104
static bool should_round_up(char const *const mantissa_base, char const *const mantissa_it, int const sign, __acrt_has_trailing_digits const trailing_digits, __acrt_rounding_mode const rounding_mode)
Definition: _fptostr.cpp:43
#define EINVAL
Definition: acclib.h:90
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define ERANGE
Definition: acclib.h:92
#define __cdecl
Definition: accygwin.h:79
__acrt_has_trailing_digits
#define _UCRT_VALIDATE_RETURN_ERRCODE(ptd, expr, errorcode)
#define FE_UPWARD
Definition: fenv.h:22
#define FE_TONEAREST
Definition: fenv.h:20
#define FE_DOWNWARD
Definition: fenv.h:21
int __cdecl fegetround(void)
result_buffer_count char *const _In_ int const _In_ bool const _In_ unsigned const _In_ STRFLT const pflt
Definition: cvt.cpp:116
_In_ size_t const _In_ int _In_ bool const _In_ unsigned const _In_ __acrt_rounding_mode const _Inout_ __crt_cached_ptd_host & ptd
Definition: cvt.cpp:355
_In_ size_t const _In_ int const _In_ bool const _In_ unsigned const _In_ __acrt_rounding_mode const rounding_mode
Definition: cvt.cpp:223
GLuint buffer
Definition: glext.h:5915
static const int digits[]
Definition: decode.c:71
#define sign(x)
Definition: mapdesc.cc:613
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
int errno_t
Definition: corecrt.h:615
size_t const buffer_count
Definition: xtoa.cpp:36