473,414 Members | 1,746 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,414 software developers and data experts.

Split double into two integers

Hi, I need to implement a function that should take a double and split
it into two integers. The decimalpart may be 0 but it may not be
greater than 0.99 and not less than 0.01. In other words, decimalparts
larger than three decimals are invalid input. I know floating point
numbers are not represented exactly in computers so this is tricky
business. This seems to work on my laptop, it's to be used by students
in an assignment to write a monetary class so it mustn't be perfect,
but I would like to hear your input.

#include <cmath>
#include <iostream>
#include <iomanip>
#include <sstream>

using namespace std;

void split_double(const double num, int& integer, int& decimals)
{
const int precision = 2;
double d1, d2;

d1 = modf(num, &d2);

if(d1 != 0.0f && (d1 0.99f || d1 < 0.01f))
cout << "d1 = " << d1 << " Error!" << endl; // TODO: Throw
exception

stringstream ss;
ss << fixed << setprecision(precision) << num;
ss >integer;
ss.ignore();
ss >decimals;
}

int main()
{
int intpart;
int decpart;

split_double(3.99, intpart, decpart);
cout << intpart << "." << decpart << endl;
split_double(3.991, intpart, decpart);
cout << intpart << "." << decpart << endl;
split_double(3.001, intpart, decpart);
cout << intpart << "." << decpart << endl;
}

$ ./foo.exe
3.99
d1 = 0.991 Error!
3.99
d1 = 0.001 Error!
3.0

Oct 15 '06 #1
6 9285
Hi Eric,

This function does what you want:

#include <cmath>

void split_double(double d, int precision,
int &integer_part, int &fractional_part)
{
integer_part = (int)d;
fractional_part = (int)( (d - integer_part) * std::pow(10,
precision) + 0.5);
}
The +0.5 in the integer cast is to achieve proper rounding. For
example, if precision is 3, then 0.4567 will round to 0.457 instead of
0.456.

If you need the function to be fast, then the call to pow() should
probably be optimized out somehow (or just hard code the function to a
particular precision).

Regards,
Markus.

Eric Lilja wrote:
Hi, I need to implement a function that should take a double and split
it into two integers. The decimalpart may be 0 but it may not be
greater than 0.99 and not less than 0.01. In other words, decimalparts
larger than three decimals are invalid input. I know floating point
numbers are not represented exactly in computers so this is tricky
business. This seems to work on my laptop, it's to be used by students
in an assignment to write a monetary class so it mustn't be perfect,
but I would like to hear your input.

#include <cmath>
#include <iostream>
#include <iomanip>
#include <sstream>

using namespace std;

void split_double(const double num, int& integer, int& decimals)
{
const int precision = 2;
double d1, d2;

d1 = modf(num, &d2);

if(d1 != 0.0f && (d1 0.99f || d1 < 0.01f))
cout << "d1 = " << d1 << " Error!" << endl; // TODO: Throw
exception

stringstream ss;
ss << fixed << setprecision(precision) << num;
ss >integer;
ss.ignore();
ss >decimals;
}

int main()
{
int intpart;
int decpart;

split_double(3.99, intpart, decpart);
cout << intpart << "." << decpart << endl;
split_double(3.991, intpart, decpart);
cout << intpart << "." << decpart << endl;
split_double(3.001, intpart, decpart);
cout << intpart << "." << decpart << endl;
}

$ ./foo.exe
3.99
d1 = 0.991 Error!
3.99
d1 = 0.001 Error!
3.0
Oct 15 '06 #2
Markus Svilans wrote:
Hi Eric,

This function does what you want:

#include <cmath>

void split_double(double d, int precision,
int &integer_part, int &fractional_part)
{
integer_part = (int)d;
fractional_part = (int)( (d - integer_part) * std::pow(10,
precision) + 0.5);
}
The +0.5 in the integer cast is to achieve proper rounding. For
example, if precision is 3, then 0.4567 will round to 0.457 instead of
0.456.
There are several rounding behaviors possible (round toward nearest,
round toward zero, round away from zero and so forth). The rounding
behavior that happens to be the "proper" one depends on the
application. And in this case, if the proper behavior to round to the
nearest three-digit decimal fractional representation, then adding 0.5
will not work for all values: for example -0.4567 will round to -0.456
even though -0.467 is closer in value.

A program can readily divide a double into integer and one-thousandth
units (rounding toward nearest represention) like so:

#include <math.h>

// d is the double
int integerUnits = d; // truncate

int fractionalUnits = fmod( round(d * 1000.0), 1000.0);

Greg

Oct 15 '06 #3
Hi Greg,

You're right, the solution I gave only rounds positive numbers
"properly."

Another possible correction is:

fractional_part = (int)( (d - integer_part) * std::pow(10, precision) +
(d 0 ? 0.5 : -0.5) );

The expression could be simplified by using a constant value (e.g. 100,
1000, or 10000) instead of the slower pow() function.

Thanks,
Markus.
Greg wrote:
Markus Svilans wrote:
Hi Eric,

This function does what you want:

#include <cmath>

void split_double(double d, int precision,
int &integer_part, int &fractional_part)
{
integer_part = (int)d;
fractional_part = (int)( (d - integer_part) * std::pow(10,
precision) + 0.5);
}
The +0.5 in the integer cast is to achieve proper rounding. For
example, if precision is 3, then 0.4567 will round to 0.457 instead of
0.456.

There are several rounding behaviors possible (round toward nearest,
round toward zero, round away from zero and so forth). The rounding
behavior that happens to be the "proper" one depends on the
application. And in this case, if the proper behavior to round to the
nearest three-digit decimal fractional representation, then adding 0.5
will not work for all values: for example -0.4567 will round to -0.456
even though -0.467 is closer in value.

A program can readily divide a double into integer and one-thousandth
units (rounding toward nearest represention) like so:

#include <math.h>

// d is the double
int integerUnits = d; // truncate

int fractionalUnits = fmod( round(d * 1000.0), 1000.0);

Greg
Oct 16 '06 #4
Markus Svilans wrote:
Hi Greg,

You're right, the solution I gave only rounds positive numbers
"properly."

Another possible correction is:

fractional_part = (int)( (d - integer_part) * std::pow(10, precision) +
(d 0 ? 0.5 : -0.5) );

The expression could be simplified by using a constant value (e.g. 100,
1000, or 10000) instead of the slower pow() function.
Another way to avoid the runtime overhead of calling pow() would be to
calculate the value as a compile time constant:

template <int Base, unsigned Exponent>
struct Power
{
const static int value = Base * Power<Base, Exponent-1>::value;
};

template <int Base>
struct Power<Base, 0>
{
const static int value = 1;
};

With the call to pow() replaced with the Power class template
"metafunction", there is no additional overhead in implementing
SplitDouble as a template function (with the desired precision
specified as its non-type parameter):

template <unsigned N>
void SplitDouble(double d, int& outInteger, int& outFraction)
{
int outInteger = d; // truncate

int outFraction = fmod( round(d * Power<10, N>::value),
Power<10, N>::value);
}

To obtain the two digit precision required in the original post, a
program would call SplitDouble like so:

int integerUnits, fractionalUnits;

SplitDouble<2>( d, integerUnits, fractionalUnits );

Greg

Oct 16 '06 #5
Eric Lilja wrote:
Hi, I need to implement a function that should take a double and split
it into two integers. The decimalpart may be 0 but it may not be
greater than 0.99 and not less than 0.01. In other words, decimalparts
larger than three decimals are invalid input. I know floating point
numbers are not represented exactly in computers so this is tricky
business. This seems to work on my laptop, it's to be used by students
in an assignment to write a monetary class so it mustn't be perfect,
Wrong approach. Monetary amounts are integers, just with a weird I/O
format.

HTH,
Michiel Salters.

Oct 16 '06 #6
"Greg" <gr****@pacbell.netwrote in message
news:11**********************@f16g2000cwb.googlegr oups.com...
: Markus Svilans wrote:
: Hi Eric,
: >
: This function does what you want:
: >
: #include <cmath>
: >
: void split_double(double d, int precision,
: int &integer_part, int &fractional_part)
: {
: integer_part = (int)d;
: fractional_part = (int)( (d - integer_part) * std::pow(10,
: precision) + 0.5);
: }
: >
: >
: The +0.5 in the integer cast is to achieve proper rounding. For
: example, if precision is 3, then 0.4567 will round to 0.457 instead
of
: 0.456.
Please see what happens with d=5.999 and precision=2:
integer_part = 5;
fractional_part = 100;
I don't think that this would be acceptable to the OP.

: There are several rounding behaviors possible (round toward nearest,
: round toward zero, round away from zero and so forth). The rounding
: behavior that happens to be the "proper" one depends on the
: application. And in this case, if the proper behavior to round to the
: nearest three-digit decimal fractional representation, then adding 0.5
: will not work for all values: for example -0.4567 will round to -0.456
: even though -0.467 is closer in value.
:
: A program can readily divide a double into integer and one-thousandth
: units (rounding toward nearest represention) like so:
:
: #include <math.h>
:
: // d is the double
: int integerUnits = d; // truncate
:
: int fractionalUnits = fmod( round(d * 1000.0), 1000.0);
Unfortunately, this doesn't work any better.
Starting with d=5.99999999, you will end up with:
integer_part = 5;
fractional_part = 0;
Neither do the subsequent proposals address the above problem.

One should first round the whole number, then proceed with
the decomposition.
One could use something like:
long long modulus = round( abs(d*1000) );
long integerUnits = modulus / 1000;
long fractionalUnits = modulus % 1000;
// ... then handle the sign as desired if d<0

But what do you want to do with the result?

If it is for display purposes, pass the double value directly
to a printing function from the standard (C or C++) library.

If it is for computation purposes, why not use fixed-point
integer arithmetic in the first place, as Michael pointed out ?
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form

Oct 16 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

12
by: jose luis fernandez diaz | last post by:
Hi, My OS is: cronos:jdiaz:tmp>uname -a HP-UX cronos B.11.11 U 9000/800 820960681 unlimited-user license I compile in 64-bits mode the program below:
22
by: Fred Ma | last post by:
I'm using the expression "int a = ceil( SomeDouble )". The man page says that ceil returns the smallest integer that is not less than SomeDouble, represented as a double. However, my...
3
by: John Salerno | last post by:
This is an example in the book I'm reading: string fullName = " Edward C Koop "; fullName = fullName.Trim(); string names = fullName.Split(' '); string firstName = names; //...
14
by: cj | last post by:
VB2003. I need a large positive integer. Which is larger int64 or double? I see int64 also apparently is known as long and will hold -9,223,372,036,854,775,808 through...
11
by: Bo Peng | last post by:
Dear C++ experts, I need to store and retrieve a meta information that can be int or double. The program would be significantly simpler if I can handle two types uniformly. Right now, I am using...
12
by: Pascal | last post by:
hello and soory for my english here is the query :"how to split a string in a random way" I try my first shot in vb 2005 express and would like to split a number in several pieces in a random way...
6
by: Johs | last post by:
I have: int a = 1; int b = 2; double c = a/b; Is it somehow possible to divide these two integers and get the result as a double 0.5? Or do they both have to be declared as doubles?
6
by: Alexander Stoyakin | last post by:
Hello, please advise on the following issue. I need to check that difference between two double values is not higher than defined limit. int main() { double limit = 0.3; double val1 = 0.5,...
22
by: Bill Reid | last post by:
I just noticed that my "improved" version of sscanf() doesn't assign floating point numbers properly if the variable assigned to is declared as a "float" rather than a "double". (This never...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.