473,669 Members | 2,386 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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(co nst 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(pr ecision) << 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 9314
Hi Eric,

This function does what you want:

#include <cmath>

void split_double(do uble d, int precision,
int &integer_par t, int &fractional_par t)
{
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(co nst 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(pr ecision) << 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(do uble d, int precision,
int &integer_par t, int &fractional_par t)
{
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(do uble d, int precision,
int &integer_par t, int &fractional_par t)
{
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
"metafuncti on", 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(dou ble 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.goo glegroups.com.. .
: Markus Svilans wrote:
: Hi Eric,
: >
: This function does what you want:
: >
: #include <cmath>
: >
: void split_double(do uble d, int precision,
: int &integer_par t, int &fractional_par t)
: {
: 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
2938
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
2989
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 understanding is that a double has nonuniform precision throughout its value range. Will a double always be able to exactly represent any value of type int? Could someone please point me to an explanation of how this is ensured, given that the details of...
3
2097
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; // Edward Two questions about this: 1. Why do you use single quotes with Split() instead of double? Is this
14
9633
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 9,223,372,036,854,775,807. But I'm not good with the E+??? notation so when I'm told double holds -1.79769313486231570E+308 through -4.94065645841246544E-324 for negative values; 4.94065645841246544E-324 through 1.79769313486231570E+308 for positive values.
11
5660
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 a single interface: void setInfo(double); // store info double info(); // retrieve info and use
12
3218
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 without success. for example if the number is 123 456 : i would like to have some random strings like theese : (12 * 10 000) + (345 * 10) + (6*1) or (123*1 000)+(4*100)+(5*10)+(6*1) etc...
6
72578
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
2913
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, val2 = 0.2; if ( (val1 - val2) limit )
22
2762
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 cropped up before, since I rarely use "float"s for anything, and hardly ever use the function for floating-point numbers in the first place; I just was messing around testing it for all cases and noticed a problem.) Anyway, it is declared and I...
0
8383
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8895
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8809
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
8658
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
5682
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 then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4206
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
2797
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2032
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
2
1788
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.