A C routine to round a float to n significant digits? - c++

Suppose I have a float. I would like to round it to a certain number of significant digits.
In my case n=6.
So say float was f=1.23456999;
round(f,6) would give 1.23457
f=123456.0001 would give 123456
Anybody know such a routine ?
Here it works on website: http://ostermiller.org/calc/significant_figures.html

Multiply the number by a suitable scaling factor to move all significant digits to the left of the decimal point. Then round and finally reverse the operation:
#include <math.h>
double round_to_digits(double value, int digits)
{
if (value == 0.0) // otherwise it will return 'nan' due to the log10() of zero
return 0.0;
double factor = pow(10.0, digits - ceil(log10(fabs(value))));
return round(value * factor) / factor;
}
Tested: http://ideone.com/fH5ebt
Buts as #PascalCuoq pointed out: the rounded value may not exactly representable as a floating point value.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *Round(float f, int d)
{
char buf[16];
sprintf(buf, "%.*g", d, f);
return strdup(buf);
}
int main(void)
{
char *r = Round(1.23456999, 6);
printf("%s\n", r);
free(r);
}
Output is:
1.23457

Something like this should work:
double round_to_n_digits(double x, int n)
{
double scale = pow(10.0, ceil(log10(fabs(x))) + n);
return round(x * scale) / scale;
}
Alternatively you could just use sprintf/atof to convert to a string and back again:
double round_to_n_digits(double x, int n)
{
char buff[32];
sprintf(buff, "%.*g", n, x);
return atof(buff);
}
Test code for both of the above functions: http://ideone.com/oMzQZZ
Note that in some cases incorrect rounding may be observed, e.g. as pointed out by #clearScreen in the comments below, 13127.15 is rounded to 13127.1 instead of
13127.2.

This should work (except the noise given by floating point precision):
#include <stdio.h>
#include <math.h>
double dround(double a, int ndigits);
double dround(double a, int ndigits) {
int exp_base10 = round(log10(a));
double man_base10 = a*pow(10.0,-exp_base10);
double factor = pow(10.0,-ndigits+1);
double truncated_man_base10 = man_base10 - fmod(man_base10,factor);
double rounded_remainder = fmod(man_base10,factor)/factor;
rounded_remainder = rounded_remainder > 0.5 ? 1.0*factor : 0.0;
return (truncated_man_base10 + rounded_remainder)*pow(10.0,exp_base10) ;
}
int main() {
double a = 1.23456999;
double b = 123456.0001;
printf("%12.12f\n",dround(a,6));
printf("%12.12f\n",dround(b,6));
return 0;
}

If you want to print a float to a string use simple sprintf(). For outputting it just to the console you can use printf():
printf("My float is %.6f", myfloat);
This will output your float with 6 decimal places.

Print to 16 significant digit.
double x = -1932970.8299999994;
char buff[100];
snprintf(buff, sizeof(buff), "%.16g", x);
std::string buffAsStdStr = buff;
std::cout << std::endl << buffAsStdStr ;

Related

How to set format of std::scientific

I want to print 12345.0 as 0.1235e+05. But the below code gives 1.23450e+04. Is there a way to control the format of std::scientific?
#include <iostream>
#include <string>
#include <sstream>
int main()
{
double a = 12345.0;
std::stringstream s;
s.precision(3);
s << std::scientific;
s << a;
std::cout << s.str() << std::endl;
return 0;
}
The output is
1.235e+04
I also tried the code here Print exponential notation with one leading zero with C++ but there is a problem about rounding. If I set precision to 4 it does not round and gives 0.1234E5 however it should have been 0.1235E5.
Any solution to this?
Then that isn't scientific form. Scientific form must produce a number between 1-10 and multiplied by a power of 10
Source: http://chemed.chem.purdue.edu/genchem/topicreview/bp/ch1/scinot.html
A problem with re-inventing double to string conversion is the many corner cases.
Consider printing values near 99995.0 to 4 places
void foo(double value, int precision) {
if (value == 0.) {
printf("%g\n", 0.0);
}
int exponent = (int) floor(log10(fabs(value)));
double base = value / pow(10, exponent);
base /= 10.0;
int p = precision;
base = round(base * pow(10, p)) / pow(10, p);
exponent++;
printf("%.*fE%d\n", p, base, exponent);
bar(value, precision);
}
foo(99994.99, 4);
foo(99995.01, 4);
Prints
0.9999E5
1.0000E5
Rather than the hoped for
0.9999E5
0.1000E6
Rather than try to out-compute the library conversion of floating point to a string, simply post process the string to the desired format.
Below is C, yet OP is looking for C++, so take this as a guide.
void bar(double value, int precision) {
precision--;
char buf[400];
snprintf(buf, sizeof buf, "%.*e", precision, value);
if (isfinite(value)) {
char *e = strchr(buf, 'e');
char *first_digit = e - precision - 2;
int expo = atoi(e + 1) + 1;
printf("%.*s0.%c%.*sE%d\n", !isdigit((unsigned char )buf[0]), buf,
*first_digit, precision, first_digit + 2, expo);
} else {
printf("%s\n", buf);
}
}
bar(99994.99, 4);
bar(99995.01, 4);
Prints
0.9999E5
0.1000E6
"If I set precision to 4 it does not round and gives 0.1234E5 however it should have been 0.1235E5."
This is a result of the default rounding mode is "round to nearest, ties to even" and OP is hoping for "round to nearest, ties to away".
Code such as base = round(base * pow(10, p)) / pow(10, p); may achieve OP's goal in select cases as the multiplication and division here can incur rounding due to imprecision, sometimes in the desired direction. This is not reliable across all double to achieve "round to nearest, ties to away".
I corrected the error in the solution given in the link Print exponential notation with one leading zero with C++ by adding two lines of code. I also repeated the process for correct formatting:
int p = stream.precision();
base = round(base * pow(10, p)) / pow(10, p);
It now makes correct rounding and gives 0.1235E5. Here is the whole code:
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <cmath>
class Double {
public:
Double(double x) : value(x) {}
const double value;
};
std::ostream& operator<< (std::ostream& stream, const Double& x) {
// So that the log does not scream
if (x.value == 0.) {
stream << 0.0;
return stream;
}
int exponent = floor(log10(std::abs(x.value)));
double base = x.value / pow(10, exponent);
// Transform here
base /= 10.0;
int p = stream.precision(); // This line is added to correct the code
base = round(base * pow(10, p)) / pow(10, p); // This line is added to correct the code
exponent += 1;
double x2 = base * pow(10, exponent);
exponent = floor(log10(std::abs(x2)));
base = x2 / pow(10, exponent);
// Transform here
base /= 10.0;
base = round(base * pow(10, p)) / pow(10, p); // This line is added to correct the code
exponent += 1;
stream << base << "+e" << exponent;
return stream;
}
int main()
{
//double a = 12345.0;
double a = 99995.01;
std::stringstream s;
s.precision(4);
s << Double(a);
std::cout << s.str() << std::endl;
return 0;
}

Using function decimal to return only decimal of input as double C++

I am on week 3 of C++ & I am so lost. I need to write a program with function decimal - that will return the decimal part of any non negative decimal number sent to it as input. Needs to be clear that it needs to return a double - parameters set at double.
we haven't learned about function decimal yet nor type coercion and trying to teach myself isn't going well.
Check the following example. You can try something like this that is pretty simple.
double num = 23.345;
int intpart = (int)num;
double decpart = num - intpart;
printf("Num = %f, intpart = %d, decpart = %f\n", num, intpart, decpart);
You can use string conversions:
#include <algorithm>
#include <iostream>
#include <string>
int main() {
float input = 12.123456;
std::string ip = std::to_string(input);
ip.erase(ip.begin(), --std::find(ip.begin(), ip.end(), '.'));
ip.front() = '0';
std::cout << ip;
return 0;
}
Another way would be simply substracting the floor of the number from itself...
#include <iostream>
#include <cmath>
int main() {
float input = 12.12;
std::cout << (input - std::floor(input));
return 0;
}
I'm not quit sure that I'm fully understand your question.
Are you having an hard time implementing this function?
If so - think about subtracting the integral part of the number from it, and in that way you will remain with the decimal part only.
Something like: (pseudo code)
double a = 10.85
int b = int(a)
return a - b
Think about the math.
A decimal number is of form a.b where a is the integral part and b the fractional part.
Suppose your input is N (= 1.234) then to extract say frac = .234 you just need to do is
frac = N - floor(N); remember floor(N) is of 1.000.
I think this is of help implement the code.
An example:
#include <iostream>
#include <cmath>
int main() {
float input;
std::cin >> input;
std::cout << (input - std::floor(input));
return 0;
}
or
as a function
#include <cmath>
double decimal(const double &N){
return (N - std::floor(N));
}

Round a double to the closest and greater float

I want to round big double number (>1e6) to the closest but bigger float using c/c++.
I tried this but I'm not sure it is always correct and there is maybe a fastest way to do that :
int main() {
// x is the double we want to round
double x = 100000000005.0;
double y = log10(x) - 7.0;
float a = pow(10.0, y);
float b = (float)x;
//c the closest round up float
float c = a + b;
printf("%.12f %.12f %.12f\n", c, b, x);
return 0;
}
Thank you.
Simply assigning a double to float and back should tell, if the float is larger. If it's not, one should simply increment the float by one unit. (for positive floats). If this doesn't still produce expected result, then the double is larger than supported by a float, in which case float should be assigned to Inf.
float next(double a) {
float b=a;
if ((double)b > a) return b;
return std::nextafter(b, std::numeric_limits<float>::infinity());
}
[Hack] C-version of next_after (on selected architectures would be)
float next_after(float a) {
*(int*)&a += a < 0 ? -1 : 1;
return a;
}
Better way to do it is:
float next_after(float a) {
union { float a; int b; } c = { .a = a };
c.b += a < 0 ? -1 : 1;
return c.a;
}
Both of these self-made hacks ignore Infs and NaNs (and work on non-negative floats only). The math is based on the fact, that the binary representations of floats are ordered. To get to next representable float, one simply increments the binary representation by one.
If you use c99, you can use the nextafterf function.
#include <stdio.h>
#include <math.h>
#include <float.h>
int main(){
// x is the double we want to round
double x=100000000005.0;
float c = x;
if ((double)c <= x)
c = nextafterf(c, FLT_MAX);
//c the closest round up float
printf("%.12f %.12f\n",c,x);
return 0;
}
C has a nice nextafter function which will help here;
float toBiggerFloat( const double a ) {
const float test = (float) a;
return ((double) test < a) ? nextafterf( test, INFINITY ) : test;
}
Here's a test script which shows it on all classes of number (positive/negative, normal/subnormal, infinite, nan, -0): http://codepad.org/BQ3aqbae (it works fine on anything is the result)

c++ convert a fractional part of a number into integer

I needed to convert a fractional part of a number into integer without a comma,
for example I have 3.35 I want to get just 35 part without zero or a comma,
Because I used the modf() function to extract the the fractional part but it gives me a 0.35
if there is any way to do that or to filter the '0.' part I will be very grateful if you show me how with the smaller code possible,
A bit more efficient than converting to a string and back again:
int fractional_part_as_int(double number, int number_of_decimal_places) {
double dummy;
double frac = modf(number,&dummy);
return round(frac*pow(10,number_of_decimal_places));
}
#include <iostream>
#include <cmath>
double round(double r) {
return (r > 0.0) ? std::floor(r + 0.5) : std::ceil(r - 0.5);
}
double floor_to_zero(double f) {
return (f > 0.0) ? std::floor(f) : std::ceil(f);
}
double sign(double s) {
return (s < 0.0) ? -1.0 : 1.0;
}
int frac(double f, int prec) {
return round((f - floor_to_zero(f)) * prec) * sign(f);
}
int main() {
double a = 1.2345;
double b = -34.567;
std::cout << frac(a, 100) << " " << frac(b, 100) << std::endl; // 23 57
}
another solution
int precision= 100;
double number = 3.35;
int f = floor(xx);
double temp = ( f - number ) * -1;
int fractional_part = temp * precision;
IF you need it as a string, a quite easy C style solution would be (should work for variable number of decimal places):
double yourNumber = 0.35f;
char buffer[32];
snprintf(buffer, 32, "%g", yourNumber);
strtok(buffer, "."); // Here we would get the part before . , should still check
char* fraction = strtok(NULL, ".");
int fractionAsInt = atoi(fraction);
This example lacks error handling in case of a bad string and is not feasible if you just need a fixed number of decimal places, since the arithmetic approaches work better there.
Something like this should work:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
static int get_frac(double value, unsigned short precision)
{
return (int)((value - (long)value) * pow(10, precision));
}
static int get_frac_no_trailing_zeros(double value, unsigned short precision)
{
int v = get_frac(value, precision);
while (v % 10 == 0)
v /= 10;
return v;
}
int main(int argc, char *argv[])
{
double v;
v = 123.4564;
printf("%.4f = %d\n", v, get_frac(v, 2));
printf("%.4f = %d\n", v, get_frac(v, 4));
printf("%.4f = %d\n", v, get_frac(v, 6));
printf("%.4f = %d\n", v, get_frac_no_trailing_zeros(v, 6));
return EXIT_SUCCESS;
}
You may also want to either avoid calling pow by having a user supply a number in a power of 10 in a first place, or use a lookup table.
Using some stl magic, here is the sample code:
typedef std::pair<int, int> SplitFloat;
SplitFloat Split(float value, int precision)
{
// Get integer part.
float left = std::floor(value);
// Get decimal part.
float right = (value - left) * float(std::pow(10, precision));
return SplitFloat(left, right);
}
It can be improved, but is pretty straightforward.
I just did something close to what you are trying to do, though I'm still pretty new. None the less, maybe this will help someone in the future as I landed here looking for results for my problem.
The first step is making sure that the variable that contains 3.35 is a double, but that's probably obvious.
Next, create a variable that is only an integer and set it's value equal to the value of the double. It will then only contain the whole number.
Then subtract the whole number (int) from the double. You will be left with the fraction/decimal value. From there, just multiply by 100.
Beyond the 100ths decimal value, you would have to do a little more configuring obviously, but it should be fairly simple to do with an if statement. If the decimal value is greater than .99, multiply 1000 instead etc..
Here's how I would do it.
#include <sstream>
#include <string>
int main()
{
double d = yourDesiredNumber; //this is your number
std::ostringstream out;
out << setprecision(yourDesiredPrecision) << std::fixed
<< std::showpoint << d;
std::istringstream in(out.str());
std::string wholePart; //you won't need this.
int fractionalPart;
std::getline(in, wholePart, '.');
in >> fractionalPart;
//now fractionalPart contains your desired value.
}
I'm pretty sure that instead of two different istringstream and ostringstream objects you could have gotten away with just one stringstream object, but I am not sure about the details (never used that class) so I didn't use it in the example.

Why do these two code snippets produce different results? (Float, Double precision)

I am only beginning to learn C++ and have been messing around with float and double values. Below are two code snippets that seem to me to be doing the same thing but give different results. What am I missing? Can someone explain the precision error the first code must have to get a different result than the second.
int _tmain(int argc, _TCHAR* argv[])
{
const float f = 0.1;
const double d = 0.1;
int counter = 0;
for(counter; ((double)counter * f - (double)counter * d) < 0.34; counter++) {}
cout << "Iterations = " << counter << "\n" ;
system("pause");
return 0;
}
int main (int argc, const char * argv[])
{
float time_f = 0.1;
double time_d = 0.1;
float total_f = 0;
double total_d = 0;
int count=0;
double difference = 0;
while (true) {
total_d = count * time_d;
total_f = count * time_f;
if(total_f - total_d >= 0.34){
break;
}
count++;
}
std::cout << count << "\n";
system("pause");
}
I have altered the cast of my for loop condition between float and double but the value does not differ.
Both float and double have a finite representation, which means they
take on a series of descrete values, and not just any real value. In
particular, in your example, 0.1 has no exact floating point
representation on any modern machine I know of (all of which use a base
which is a power of 2 in their implementation—0.1 is 1/5 *
1/2, and nothing which is a multiple of 1/5 can have a finite
representation unless the base is a multiple of 5).
The result is that either float and double have the same underlying
representation (not usually the case), or there will be a difference as
soon as count is different from 0.
The usual reference for this subject is
“What
Every Computer Scientist Should Know About Floating-Point
Arithmetic”. Until you've read and understood (or at least
understood the implications) it, you shouldn't touch machine floating
point.
Difference between that two code snippets is in cast. counter * f is casted to double in first snippet and stored to float variable in second one.
Here's an example of how it could look like:
#include <stdio.h>
int main(int argc, char* argv[])
{
const float f = 0.1;
const double d = 0.1;
int count = 0;
for(count; (double)(count * f) - (double)(count * d) < 0.34; count++);
printf("Iterations = %d\n", count);
count = 0;
while (true)
{
double total_d = count * d; // is equal to (double)(count * d)
double total_f = count * f; // is equal to (double)(count * f)
if (total_f - total_d >= 0.34)
break;
count++;
}
printf("Iterations = %d\n", count);
return 0;
}
You haven't casted count to double here:
total_d = count * time_d;
total_f = count * time_f;
Another thing, those loops will never end since both subtraction operands have the same value :S