11

Is it possible to format string in scientific notation in the following ways:

  • set fixed places in exponent: 1

  • set fixed decimal places in mantissa: 0

     double number = 123456.789
    

So the number should be formated

  1e+5

I am not able to set 0 decimal points for mantissa:

cout.precision(0);
cout << scientific << number;

result:

1.234568e+005
user202729
  • 3,358
  • 3
  • 25
  • 36
abcdef
  • 319
  • 2
  • 3
  • 11

5 Answers5

8

I can't figure out how to get a single digit in the exponent field but the following matches all your other requirements.

#include <iostream>
#include <iomanip>

int main()
{
  const double number = 123456.789;

  std::cout << std::setprecision(0) << std::scientific << number << std::endl;
}

Output:

1e+05

EDIT:
Did a quick search through the standard (N3291) and couldn't find anything that talked about the number of digits in the exponent field when using scientific notation. This might be implementation defined.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
5

You can easily do this with the {fmt} formatting library:

#include <fmt/core.h>

double number = 123456.789;
auto s = fmt::format("{:.0e}\n", number); // s == "1e+05"
s.erase(s.size() - 2, 1); // s == "1e+5"

A formatting facility based on this library is proposed for standardization in C++20: P0645.

Disclaimer: I'm the author of {fmt}.

vitaut
  • 49,672
  • 25
  • 199
  • 336
3

I'm not sure what C++ compiler you're using that's giving you 3 digits for the exponent—the C and C++ standards require a minimum of 2 digits for that, and that's what g++ does. There's no way to get only one digit using the standard C or C++ I/O functions, so you'll have to roll your own solution. Since doing a floating-point to string conversion is a very tricky problem [PDF], I'd strongly recommend not doing that and postprocessing the result instead.

Here's one way to do that:

// C version; you can rewrite this to use std::string in C++ if you want
void my_print_scientific(char *dest, size_t size, double value)
{
    // First print out using scientific notation with 0 mantissa digits
    snprintf(dest, size, "%.0e", value);

    // Find the exponent and skip the "e" and the sign
    char *exponent = strchr(dest, 'e') + 2;

    // If we have an exponent starting with 0, drop it
    if(exponent != NULL && exponent[0] == '0')
    {
        exponent[0] = exponent[1];
        exponent[1] = '\0';
    }
}
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
2

You can actualy format anything once you have a string.. more c++ code would look like:

const double number = 123456.789;
const int expSize = 1;
std::ostringstream oss;
std::string output;
oss << std::scientific << number;
unsigned int ePos = oss.str().find("e");
unsigned int dPos = oss.str().find(".");
if(ePos == 0){
    //no exponent
}
else if(dPos == 0){
    //not decimal
}
else{
    output = oss.str().substr(0, dPos) + oss.str().substr(ePos, 2);
    if(oss.str().size()-expSize > ePos+1)
        output += oss.str().substr(oss.str().size()-expSize, oss.str().size());
    else{
        //expSize too big (or bug -> e used but no exponent?)
    }
    std::cout << output;
}

Output:

1e+5

You can set exponent size in expSize and this works for arbitrary large exponent.

Hope it helps!

Raven
  • 4,783
  • 8
  • 44
  • 75
1

Here is a stream solution:

#include <iostream>
#include <iomanip>
using namespace std;

template<typename T>
struct scientificNumberType
{
    explicit scientificNumberType(T number, int decimalPlaces) : number(number), decimalPlaces(decimalPlaces) {}

    T number;
    int decimalPlaces;
};

template<typename T>
scientificNumberType<T> scientificNumber(T t, int decimalPlaces)
{
    return scientificNumberType<T>(t, decimalPlaces);
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const scientificNumberType<T>& n)
{
    double numberDouble = n.number;

    int eToThe = 0;
    for(; numberDouble > 9; ++eToThe)
    {
        numberDouble /= 10;
    }

    // memorize old state
    std::ios oldState(nullptr);
    oldState.copyfmt(os);

    os << std::fixed << std::setprecision(n.decimalPlaces) << numberDouble << "e" << eToThe;

    // restore state
    os.copyfmt(oldState);

    return os;
}

Usage sample:

int main()
{
    double e = 1.234;

    cout << scientificNumber(e, 1) << " " << scientificNumber(e, 3);

    return 0;
}

Output: 1.2e0 1.234e0

IceFire
  • 4,016
  • 2
  • 31
  • 51