@@ -433,27 +433,28 @@ bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
433
433
}
434
434
// Multiple conversions may be needed to get the right number of
435
435
// effective rounded fractional digits.
436
- int extraDigits{0 };
437
436
bool canIncrease{true };
438
- while ( true ) {
437
+ for ( int extraDigits{fracDigits == 0 ? 1 : 0 };; ) {
439
438
decimal::ConversionToDecimalResult converted{
440
439
ConvertToDecimal (extraDigits + fracDigits, rounding, flags)};
441
- if (IsInfOrNaN (converted.str , static_cast <int >(converted.length ))) {
440
+ const char *convertedStr{converted.str };
441
+ if (IsInfOrNaN (convertedStr, static_cast <int >(converted.length ))) {
442
442
return editWidth > 0 &&
443
443
converted.length > static_cast <std::size_t >(editWidth)
444
444
? EmitRepeated (io_, ' *' , editWidth)
445
445
: EmitPrefix (edit, converted.length , editWidth) &&
446
- EmitAscii (io_, converted. str , converted.length ) &&
446
+ EmitAscii (io_, convertedStr , converted.length ) &&
447
447
EmitSuffix (edit);
448
448
}
449
449
int expo{converted.decimalExponent + edit.modes .scale /* kP*/ };
450
- int signLength{*converted. str == ' -' || *converted. str == ' +' ? 1 : 0 };
450
+ int signLength{*convertedStr == ' -' || *convertedStr == ' +' ? 1 : 0 };
451
451
int convertedDigits{static_cast <int >(converted.length ) - signLength};
452
452
if (IsZero ()) { // don't treat converted "0" as significant digit
453
453
expo = 0 ;
454
454
convertedDigits = 0 ;
455
455
}
456
- int trailingOnes{0 };
456
+ bool isNegative{*convertedStr == ' -' };
457
+ char one[2 ];
457
458
if (expo > extraDigits && extraDigits >= 0 && canIncrease) {
458
459
extraDigits = expo;
459
460
if (!edit.digits .has_value ()) { // F0
@@ -462,24 +463,45 @@ bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
462
463
canIncrease = false ; // only once
463
464
continue ;
464
465
} else if (expo == -fracDigits && convertedDigits > 0 ) {
465
- if ((rounding == decimal::FortranRounding::RoundUp &&
466
- *converted.str != ' -' ) ||
467
- (rounding == decimal::FortranRounding::RoundDown &&
468
- *converted.str == ' -' ) ||
469
- (rounding == decimal::FortranRounding::RoundToZero &&
470
- rounding != edit.modes .round && // it changed below
471
- converted.str [signLength] >= ' 5' )) {
472
- // Round up/down to a scaled 1
466
+ // Result will be either a signed zero or power of ten, depending
467
+ // on rounding.
468
+ char leading{convertedStr[signLength]};
469
+ bool roundToPowerOfTen{false };
470
+ switch (edit.modes .round ) {
471
+ case decimal::FortranRounding::RoundUp:
472
+ roundToPowerOfTen = !isNegative;
473
+ break ;
474
+ case decimal::FortranRounding::RoundDown:
475
+ roundToPowerOfTen = isNegative;
476
+ break ;
477
+ case decimal::FortranRounding::RoundToZero:
478
+ break ;
479
+ case decimal::FortranRounding::RoundNearest:
480
+ if (leading == ' 5' &&
481
+ rounding == decimal::FortranRounding::RoundNearest) {
482
+ // Try again, rounding away from zero.
483
+ rounding = isNegative ? decimal::FortranRounding::RoundDown
484
+ : decimal::FortranRounding::RoundUp;
485
+ extraDigits = 1 - fracDigits; // just one digit needed
486
+ continue ;
487
+ }
488
+ roundToPowerOfTen = leading > ' 5' ;
489
+ break ;
490
+ case decimal::FortranRounding::RoundCompatible:
491
+ roundToPowerOfTen = leading >= ' 5' ;
492
+ break ;
493
+ }
494
+ if (roundToPowerOfTen) {
473
495
++expo;
474
- convertedDigits = 0 ;
475
- trailingOnes = 1 ;
476
- } else if (rounding != decimal::FortranRounding::RoundToZero) {
477
- // Convert again with truncation so first digit can be checked
478
- // on the next iteration by the code above
479
- rounding = decimal::FortranRounding::RoundToZero;
480
- continue ;
496
+ convertedDigits = 1 ;
497
+ if (signLength > 0 ) {
498
+ one[0 ] = *convertedStr;
499
+ one[1 ] = ' 1' ;
500
+ } else {
501
+ one[0 ] = ' 1' ;
502
+ }
503
+ convertedStr = one;
481
504
} else {
482
- // Value rounds down to zero
483
505
expo = 0 ;
484
506
convertedDigits = 0 ;
485
507
}
@@ -493,17 +515,14 @@ bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
493
515
int digitsAfterPoint{convertedDigits - digitsBeforePoint};
494
516
int trailingZeroes{flags & decimal::Minimize
495
517
? 0
496
- : std::max (0 ,
497
- fracDigits -
498
- (zeroesAfterPoint + digitsAfterPoint + trailingOnes))};
518
+ : std::max (0 , fracDigits - (zeroesAfterPoint + digitsAfterPoint))};
499
519
if (digitsBeforePoint + zeroesBeforePoint + zeroesAfterPoint +
500
- digitsAfterPoint + trailingOnes + trailingZeroes ==
520
+ digitsAfterPoint + trailingZeroes ==
501
521
0 ) {
502
522
zeroesBeforePoint = 1 ; // "." -> "0."
503
523
}
504
524
int totalLength{signLength + digitsBeforePoint + zeroesBeforePoint +
505
- 1 /* '.'*/ + zeroesAfterPoint + digitsAfterPoint + trailingOnes +
506
- trailingZeroes};
525
+ 1 /* '.'*/ + zeroesAfterPoint + digitsAfterPoint + trailingZeroes};
507
526
int width{editWidth > 0 ? editWidth : totalLength};
508
527
if (totalLength > width) {
509
528
return EmitRepeated (io_, ' *' , width);
@@ -513,13 +532,12 @@ bool RealOutputEditing<KIND>::EditFOutput(const DataEdit &edit) {
513
532
++totalLength;
514
533
}
515
534
return EmitPrefix (edit, totalLength, width) &&
516
- EmitAscii (io_, converted. str , signLength + digitsBeforePoint) &&
535
+ EmitAscii (io_, convertedStr , signLength + digitsBeforePoint) &&
517
536
EmitRepeated (io_, ' 0' , zeroesBeforePoint) &&
518
537
EmitAscii (io_, edit.modes .editingFlags & decimalComma ? " ," : " ." , 1 ) &&
519
538
EmitRepeated (io_, ' 0' , zeroesAfterPoint) &&
520
- EmitAscii (io_, converted. str + signLength + digitsBeforePoint,
539
+ EmitAscii (io_, convertedStr + signLength + digitsBeforePoint,
521
540
digitsAfterPoint) &&
522
- EmitRepeated (io_, ' 1' , trailingOnes) &&
523
541
EmitRepeated (io_, ' 0' , trailingZeroes) &&
524
542
EmitRepeated (io_, ' ' , trailingBlanks_) && EmitSuffix (edit);
525
543
}
0 commit comments