@@ -159,13 +159,10 @@ bool RealOutputEditingBase::EmitSuffix(const DataEdit &edit) {
159
159
160
160
template <int binaryPrecision>
161
161
decimal::ConversionToDecimalResult RealOutputEditing<binaryPrecision>::Convert(
162
- int significantDigits, const DataEdit &edit, int flags) {
163
- if (edit.modes .editingFlags & signPlus) {
164
- flags |= decimal::AlwaysSign;
165
- }
162
+ int significantDigits, enum decimal::FortranRounding rounding, int flags) {
166
163
auto converted{decimal::ConvertToDecimal<binaryPrecision>(buffer_,
167
164
sizeof buffer_, static_cast <enum decimal::DecimalConversionFlags>(flags),
168
- significantDigits, edit. modes . round , x_)};
165
+ significantDigits, rounding , x_)};
169
166
if (!converted.str ) { // overflow
170
167
io_.GetIoErrorHandler ().Crash (
171
168
" RealOutputEditing::Convert : buffer size %zd was insufficient" ,
@@ -181,6 +178,9 @@ bool RealOutputEditing<binaryPrecision>::EditEorDOutput(const DataEdit &edit) {
181
178
int editWidth{edit.width .value_or (0 )}; // 'w' field
182
179
int significantDigits{editDigits};
183
180
int flags{0 };
181
+ if (edit.modes .editingFlags & signPlus) {
182
+ flags |= decimal::AlwaysSign;
183
+ }
184
184
if (editWidth == 0 ) { // "the processor selects the field width"
185
185
if (edit.digits .has_value ()) { // E0.d
186
186
editWidth = editDigits + 6 ; // -.666E+ee
@@ -204,7 +204,7 @@ bool RealOutputEditing<binaryPrecision>::EditEorDOutput(const DataEdit &edit) {
204
204
// In EN editing, multiple attempts may be necessary, so it's in a loop.
205
205
while (true ) {
206
206
decimal::ConversionToDecimalResult converted{
207
- Convert (significantDigits, edit, flags)};
207
+ Convert (significantDigits, edit. modes . round , flags)};
208
208
if (IsInfOrNaN (converted)) {
209
209
return EmitPrefix (edit, converted.length , editWidth) &&
210
210
io_.Emit (converted.str , converted.length ) && EmitSuffix (edit);
@@ -261,7 +261,11 @@ template <int binaryPrecision>
261
261
bool RealOutputEditing<binaryPrecision>::EditFOutput(const DataEdit &edit) {
262
262
int fracDigits{edit.digits .value_or (0 )}; // 'd' field
263
263
const int editWidth{edit.width .value_or (0 )}; // 'w' field
264
+ enum decimal::FortranRounding rounding{edit.modes .round };
264
265
int flags{0 };
266
+ if (edit.modes .editingFlags & signPlus) {
267
+ flags |= decimal::AlwaysSign;
268
+ }
265
269
if (editWidth == 0 ) { // "the processor selects the field width"
266
270
if (!edit.digits .has_value ()) { // F0
267
271
flags |= decimal::Minimize;
@@ -274,40 +278,59 @@ bool RealOutputEditing<binaryPrecision>::EditFOutput(const DataEdit &edit) {
274
278
bool canIncrease{true };
275
279
while (true ) {
276
280
decimal::ConversionToDecimalResult converted{
277
- Convert (extraDigits + fracDigits, edit , flags)};
281
+ Convert (extraDigits + fracDigits, rounding , flags)};
278
282
if (IsInfOrNaN (converted)) {
279
283
return EmitPrefix (edit, converted.length , editWidth) &&
280
284
io_.Emit (converted.str , converted.length ) && EmitSuffix (edit);
281
285
}
282
286
int scale{IsZero () ? 1 : edit.modes .scale }; // kP
283
287
int expo{converted.decimalExponent + scale};
288
+ int signLength{*converted.str == ' -' || *converted.str == ' +' ? 1 : 0 };
289
+ int convertedDigits{static_cast <int >(converted.length ) - signLength};
290
+ int trailingOnes{0 };
284
291
if (expo > extraDigits && extraDigits >= 0 && canIncrease) {
285
292
extraDigits = expo;
286
293
if (!edit.digits .has_value ()) { // F0
287
294
fracDigits = sizeof buffer_ - extraDigits - 2 ; // sign & NUL
288
295
}
289
296
canIncrease = false ; // only once
290
297
continue ;
298
+ } else if (expo == -fracDigits && convertedDigits > 0 ) {
299
+ if (rounding != decimal::FortranRounding::RoundToZero) {
300
+ // Convert again without rounding so that we can round here
301
+ rounding = decimal::FortranRounding::RoundToZero;
302
+ continue ;
303
+ } else if (converted.str [signLength] >= ' 5' ) {
304
+ // Value rounds up to a scaled 1 (e.g., 0.06 for F5.1 -> 0.1)
305
+ ++expo;
306
+ convertedDigits = 0 ;
307
+ trailingOnes = 1 ;
308
+ } else {
309
+ // Value rounds down to zero
310
+ expo = 0 ;
311
+ convertedDigits = 0 ;
312
+ }
291
313
} else if (expo < extraDigits && extraDigits > -fracDigits) {
292
314
extraDigits = std::max (expo, -fracDigits);
293
315
continue ;
294
316
}
295
- int signLength{*converted.str == ' -' || *converted.str == ' +' ? 1 : 0 };
296
- int convertedDigits{static_cast <int >(converted.length ) - signLength};
297
317
int digitsBeforePoint{std::max (0 , std::min (expo, convertedDigits))};
298
318
int zeroesBeforePoint{std::max (0 , expo - digitsBeforePoint)};
299
319
int zeroesAfterPoint{std::min (fracDigits, std::max (0 , -expo))};
300
320
int digitsAfterPoint{convertedDigits - digitsBeforePoint};
301
321
int trailingZeroes{flags & decimal::Minimize
302
322
? 0
303
- : std::max (0 , fracDigits - (zeroesAfterPoint + digitsAfterPoint))};
323
+ : std::max (0 ,
324
+ fracDigits -
325
+ (zeroesAfterPoint + digitsAfterPoint + trailingOnes))};
304
326
if (digitsBeforePoint + zeroesBeforePoint + zeroesAfterPoint +
305
- digitsAfterPoint + trailingZeroes ==
327
+ digitsAfterPoint + trailingOnes + trailingZeroes ==
306
328
0 ) {
307
329
zeroesBeforePoint = 1 ; // "." -> "0."
308
330
}
309
331
int totalLength{signLength + digitsBeforePoint + zeroesBeforePoint +
310
- 1 /* '.'*/ + zeroesAfterPoint + digitsAfterPoint + trailingZeroes};
332
+ 1 /* '.'*/ + zeroesAfterPoint + digitsAfterPoint + trailingOnes +
333
+ trailingZeroes};
311
334
int width{editWidth > 0 ? editWidth : totalLength};
312
335
if (totalLength > width) {
313
336
return io_.EmitRepeated (' *' , width);
@@ -323,6 +346,7 @@ bool RealOutputEditing<binaryPrecision>::EditFOutput(const DataEdit &edit) {
323
346
io_.EmitRepeated (' 0' , zeroesAfterPoint) &&
324
347
io_.Emit (
325
348
converted.str + signLength + digitsBeforePoint, digitsAfterPoint) &&
349
+ io_.EmitRepeated (' 1' , trailingOnes) &&
326
350
io_.EmitRepeated (' 0' , trailingZeroes) &&
327
351
io_.EmitRepeated (' ' , trailingBlanks_) && EmitSuffix (edit);
328
352
}
@@ -337,8 +361,12 @@ DataEdit RealOutputEditing<binaryPrecision>::EditForGOutput(DataEdit edit) {
337
361
if (!edit.width .has_value () || (*edit.width > 0 && significantDigits == 0 )) {
338
362
return edit; // Gw.0 -> Ew.0 for w > 0
339
363
}
364
+ int flags{0 };
365
+ if (edit.modes .editingFlags & signPlus) {
366
+ flags |= decimal::AlwaysSign;
367
+ }
340
368
decimal::ConversionToDecimalResult converted{
341
- Convert (significantDigits, edit)};
369
+ Convert (significantDigits, edit. modes . round , flags )};
342
370
if (IsInfOrNaN (converted)) {
343
371
return edit;
344
372
}
@@ -365,7 +393,7 @@ DataEdit RealOutputEditing<binaryPrecision>::EditForGOutput(DataEdit edit) {
365
393
template <int binaryPrecision>
366
394
bool RealOutputEditing<binaryPrecision>::EditListDirectedOutput(
367
395
const DataEdit &edit) {
368
- decimal::ConversionToDecimalResult converted{Convert (1 , edit)};
396
+ decimal::ConversionToDecimalResult converted{Convert (1 , edit. modes . round )};
369
397
if (IsInfOrNaN (converted)) {
370
398
return EditEorDOutput (edit);
371
399
}
0 commit comments