-8

I have integer number, for example 1234, but in reality it means 123.4, so it's encoded decimal and I should multiply to 10^-1.

How can I convert this int to string "123.4" easily? I should have "123.4" exactly, not "123.3999999". So I need something like itoa but more advanced.

upd by string I mean char array.

Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305
  • 4
    For positive integers, `std::to_string(1234 / 10) + "." + std::to_string(1234 % 10)`. For negatives, do this on the absolute value and prepend a `"-"`. – T.C. Sep 04 '14 at 18:52
  • 2
    What did you try, where you were stuck in particular? If we keep requiring this from rep 1 users, I don't see a point, why you should be over these minimal requirements for asking! – πάντα ῥεῖ Sep 04 '14 at 18:54
  • @T.C. at least it would be nice to use http://www.cplusplus.com/reference/cstdlib/div/ instead of deviding 1234 to 10 twice? – Oleg Vazhnev Sep 04 '14 at 18:58
  • @javapowered I suspect that doing the division and modulo directly will inline better than calling a library function; and I personally find it easier to understand as well. – T.C. Sep 04 '14 at 19:04
  • 1
    i think I probably better to use regular `itoa` but then insert '.' myself – Oleg Vazhnev Sep 04 '14 at 19:05
  • There're still the [`std::floor()`](http://en.cppreference.com/w/cpp/numeric/math/floor) and [`std::ceil()`](http://en.cppreference.com/w/cpp/numeric/math/ceil) functions available, to fix _rounding inaccuracies_. – πάντα ῥεῖ Sep 04 '14 at 19:15
  • @πάνταῥεῖ The problem is that `123.4` is not exactly representable in floating point. – T.C. Sep 04 '14 at 19:18
  • @T.C. Then the answer is probably using the stream formatting functions to get it represented correctly (no matter that the OP insists, these are _"unacceptably slow"_ for his usecase). – πάντα ῥεῖ Sep 04 '14 at 19:20

7 Answers7

3

Convert the number to a std::string:

char buffer[12];
std::string s = itoa(1234, buffer, 10);

Or:

std::string s = std::to_string(intNum);

Then simply insert() the decimal character into it:

s.insert(s.length()-1, "."); 

Or:

s.insert(s.length()-1, 1, '.'); 
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • `itoa` writes to `char *` so I can't call `.length()`, probably I should call `strlen` or something like this. also `insert` for char* is not defined too – Oleg Vazhnev Sep 05 '14 at 07:21
  • Look again more carefully at my example. `itoa()` does return a `char*` to the buffer being written to, but that `char*` is being assigned to a `std::string`, which does have `length()` and `insert()` methods. – Remy Lebeau Sep 05 '14 at 15:06
2

Dividing by 10 can cause precision loss if the numbers exceed the float point precision of the CPU. Instead, use something like this:

string intNumStr = itoa(intNum);
char lastDigit = intNumStr[intNumStr.length() - 1];
intNumStr[intNumStr.length() - 1] = '.';
intNumStr += string(lastDigit);
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
ventsyv
  • 3,316
  • 3
  • 27
  • 49
1

I was curious about the relative performance of these conversions so I did a few tests with the naive versions of a few methods. A few notes and caveats:

  • The below conversion codes have no error checking and haven't been tested (i.e., don't copy/paste the code).
  • Some methods only work for positive integers.
  • The methods do not have equivalent output. For example numbers 0-9 ('0.0', '.0', '.') and factors of 10 ('10', '10.', '10.0'). You should decide exactly what output you want for these cases.
  • I would start by choosing the simplest algorithm and only optimize once it is found I need to. Do you really need performance of ~100 million integers/second?
  • Unfortunately, I don't have a C++11 compiler to test the std::to_string() versions.

Algorithms tested are:

string toString1 (const int a)
{
    char buffer[32];
    string result = itoa(a, buffer, 10);
    char lastDigit = result[result.length() - 1];
    result[result.length() - 1] = '.';
    result += lastDigit;

    return result;
}

void toString1a (string& Output, const int a)
{
    char buffer[32];
    Output = itoa(a, buffer, 10);
    char lastDigit = Output[Output.length() - 1];
    Output[Output.length() - 1] = '.';
    Output += lastDigit;
}

string toString2 (const int a) {
    float f = a * 0.1f;
    ostringstream ss;
    ss << f;

    return ss.str();
}    

const char* toString3 (const int a)
{
    static char s_buffer[32]; //Careful!

    itoa(a, s_buffer, 10);
    size_t len = strlen(s_buffer);
    char lastDigit = s_buffer[len-1];
    s_buffer[len-1] = '.';
    s_buffer[len] = lastDigit;
    s_buffer[len+1] = '\0';

    return s_buffer;
}    

const char* toString4 (char* pBuffer, const int a)
{
    itoa(a, pBuffer, 10);
    size_t len = strlen(pBuffer);
    char lastDigit = pBuffer[len-1];
    pBuffer[len-1] = '.';
    pBuffer[len] = lastDigit;
    pBuffer[len+1] = '\0';

    return pBuffer;
}

void toString4a (char* pBuffer, const int a)
{
    itoa(a, pBuffer, 10);
    size_t len = strlen(pBuffer);
    char lastDigit = pBuffer[len-1];
    pBuffer[len-1] = '.';
    pBuffer[len] = lastDigit;
    pBuffer[len+1] = '\0';
}

const char* toString5 (char* pBuffer, const int a)
{
    snprintf(pBuffer, 16, "%.1f", a/10.0);
    return pBuffer;
}

const char* toString6 (char* pBuffer, const int a)
{
    snprintf(pBuffer, 16, "%d.%01d", a / 10, a % 10);
    return pBuffer;
}

string toString7 (const int a)
{
    ostringstream stream;
    stream << (a / 10) << '.' << (a % 10);
    return stream.str();
}

string toString8 (const int a)
{
    char buffer[16];
    string result = _itoa(a, buffer, 10);
    result.insert(result.length()-1, 1, '.'); 
    return result;
}

Basic benchmarks were run on the above methods for 100 million integers (starting from 0). If performance really matters for your case please profile/benchmark for yourself for your exact use-case.

  • toString1 = 0.64 sec (itoa to string)
  • toString1a = 0.61 sec (inplace, no return)
  • toString2 = 33.4 sec (stringstream, ouch!)
  • toString3 = 0.52 sec (itoa, static buffer)
  • toString4 = 0.52 sec (itoa)
  • toString4a = 0.52 sec (itoa, inplace)
  • toString5 = 6.35 sec (snprintf, float)
  • toString6 = 2.29 sec (snprintf, two ints)
  • toString7 = 33.3 sec (stringstream, two ints)
  • toString8 = 0.70 sec (itoa and string::insert)

Which one is "better" really depends on what you need. Personally I would use the simplest stream case (toString7) unless I was absolutely sure I needed the performance of the other methods.

uesp
  • 6,194
  • 20
  • 15
0
#include <sstream>
#include <iostream>
#include <string>
using namespace std;

string toString(int a) {
    float f = a * 0.1f;
    ostringstream ss;
    ss << f;
    return ss.str();
}

int main() {
    cout << toString(101);
    return 0;
}
Ammaro
  • 370
  • 2
  • 14
0

For c++11 you can use this:

std::string toString( int i )
{
    int t = abs( i );
    return ( i < 0 ? "-", "" ) + std::to_string( t / 10 ) + "." + std::to_string( t % 10 );
}

for pre c++11 you can replace it with std::stringstream or snprintf:

std::string toString( int i )
{
    char buffer[128] = { '-' };
    int t = abs( i );
    snprintf( buffer + 1, sizeof(buffer) - 1, "%d.%d", t / 10, t % 10 );
    return std::string( i < 0 ? buffer : buffer + 1 );
}
Slava
  • 43,454
  • 1
  • 47
  • 90
0
#include <sstream>
using namespace std;

string Decimal1ToString(int i)
{
    ostringstream stream;
    stream << (i / 10) << '.' << (i % 10);
    return stream.str();
}

Note the use of integer / and %. This prevents precision loss.

Louis Newstrom
  • 172
  • 1
  • 1
  • 13
0

This is my version:

#include <iostream>

int main()
{
    char price[18];
    _itoa_s(98321, price, 10);
    int len = strlen(price);
    char lastDigit = price[len - 1];
    price[len - 1] = '.';
    price[len] = lastDigit;
    price[len + 1] = 0;

    printf(price);

    return 0;
}
Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305