printing floating point numbers using scientific notation depending on size - c

I'm storing the result of a calculation inside a long double variable that I need to print out. I need a way to discriminate between large numbers and small numbers. For example If I want to print tan(pi/4) it should be 1, the same for the result of a multiplication like '5*3' I want to be 15 without trailing zeros. On the other hand, I want to represent small numbers like the elementary charge 1.602176634e-19 using the scientific notation. This is what I tried
void print(long double number) {
long double i;
long double tmp = ceil(number);
if (fabs(number-tmp) < 0.00000001)
number = tmp;
long double r = modfl(number, &i);
if (fabs(r) <.0000000000000001 && fabs(r) <.00001)
printf("%.Lf ", i);
else if (fabs(r) <.00001)
printf("%.Lf ", i);
else printf("%.19Lf ", number);
}
If I try to print the mass of a proton 1.6726219236951e-27 with this code I get 0, the rest of the quantities I mentioned before are displayed correctly.

Related

C - Float Imprecision, How to lock the decimal places for calculations?

I was making a little program to test floats in the C: The program itself is very simple, I just want to based on the User's input, return how much Dollar(s), Quarter(s)... etc, his number has.
//------------------------------> First Part: All the necessary Variables <-----------------------------
int main (void)
{
//Getting the user Input
float number = get_float("Number: ");
//Checking if is a positive number
if (number < 0)
{
printf("A positive number, Please: ");
}
//Declaring my Constant/Temporary variables.
float coinValues[] = {1.00, 0.25, 0.10, 0.5, 0.01};
char *coinNames[] = {"Dollar(s): ", "Quarter(s): ", "Dime(s): ", "Nickel(s): ", "Penny(ies): "};
int i = 0;
int tmp = 0;
//-----------------------------------> Second Part: The code Itself <-----------------------------------
//Checking/Printing the necessary coins.
while (number > 0)
{
//Until the loop stops, check if the number can be divided by the CoinValue.
if (number >= coinValues[i])
{
//Print the current Coin Name from the divided value.
printf("%s", coinNames[i]);
//Check if the Current Number still contains Coin Values inside of it, if True counts one in your "Coin Score".
while (number >= coinValues[i])
{
number -= coinValues[i];
tmp++;
}
//Print the Current "Coin Score", then resets TMP.
printf("%i\n", tmp);
tmp = 0;
}
else
{
//Updating the Coin value
i++;
}
}
}
My program was running very well as long I use Integers, but when I converted this code for Floats the values (Dime(s), Nickel(s), and Penny(ies)) start to return non-expected results in the Int variable tmp.
An expected result for a number like 2.6, will be 2 Dollars, 2 Quarters, and 1 Dime, but sometimes, instead of use the Dime(s), the program skips them entire and make the operation with the Nickel(s), however, what is bugging me is that the program is always returning AWL=+ without any value and then the program stay froze forever.
Considering that my only thought is that I'm "suffering" from Float Imprecision, and I don't know how to solve it, so can anyone Help me?
Ps. The program needs to always return the maximum value from each coin before pass forward.
Floating-point arithmetic is designed to approximate real-number arithmetic. IEEE 754-2008 says “Floating-point arithmetic is a systematic approximation of real arithmetic…” So there is no way to “lock” decimal digits in binary floating-point. It is intended to be used where you want an approximation, such as modeling physics. That even includes some financial applications, such as options evaluation. Although floating-point arithmetic can be used for exact calculations in some situations, these require particular care and are generally only pursued in special circumstances.
So the answer to your question on how to lock decimal places is there is no good way to do that with binary floating-point. Attempting to do so generally just yields the same effects as integer arithmetic but less efficiently and with more difficult code. So use integer arithmetic and scale the amounts according to the smallest unit of currency desired, such as a penny.

Decimal precision using integer

I am programming a uC in C language and I need to show a float number with 4 precision digits. The thing here is that my number is not really a float type. I have the integer part and the decimal part of the number in two different integer variables. Let say: int digit and int decimal.
I tried using printf ("%d.%d"); That works fine when my decimal number is 6524, but the problem comes when it is exactly 65 since it doesnt show 4 decimals.
I tried using printf ("%d.%04d"); but when my decimal part is exactly 65 it shows 0065 which is not mathematically correct (I would need 6500)
I looked for any argument of printf which completes with zeros at the end but could not find anything. All of them complete with leading zeros which is not useful for me in this case.
I also though about checking if my number is minor that 10, 100 or 1000 and multiply it by 1000, 100 or 10 respectively. But it will not work when the decimal part is exactly 0, since 0*1000 will still be 0 and not 0000.
Any idea on how to solve this? Please let me know if I am not completely clear and I will provide more information
Thanks!
Since printf returns the number of characters printed, you can do it, somewhat clumsily, as follows:
printf("%d.", int_part);
int digits = printf("%d", frac_part);
while (digits++ < 4) putchar('0');
I have to say, though, that it is a very eccentric form of representing a floating point number, and you might seriously want to rethink it.
Another wired possibility is to convert the decimal part to a string and then fill it with 0:
int main() {
int i, d, len;
char p[10];
i = 189;
d = 51;
// convert the number to string and count the digits
snprintf(p, 10, "%d", d);
len = strlen(p);
while (len < 4) {p[len] = '0'; len++;}
p[len] = '\0';
fprintf(stdout, "%d.%s\n", i, p);
// you can also go back to int
d = atoi(p);
fprintf(stdout, "%d.%d\n", i, d);
}
Combine both your answers: multiply by 10, 100 or 1000 as necessary, but still print with %04d.

input in C programming language

I want code receive from user a floating number but store only two digit after decimal point
for example if user input
a=123.123456789
a value will equal 123.12
#include <stdio.h>
int func(int x,int digit,int con,char* s)
{
int v;
v=x/digit;
v=v*digit;
x-=v;
if(con==1){
printf("%d %s(s) de R$ %.2f\n",(v/digit),s,(float)digit/100);
return x;
}
printf("%d %s(s) de R$ %.2f\n",(v/digit),s,(float)digit);
return x;
}
int main() {
int x=0;
float y;//if change to double the result will be true
scanf("%f",&y);
//y = ((int)(100.0 * y)) / 100.0;
x=(int)y;
y=y-x;
printf("NOTAS:\n");
char* arr="nota";
x=func(x,100,0,arr);
x=func(x,50,0,arr);
x=func(x,20,0,arr);
x=func(x,10,0,arr);
x=func(x,5,0,arr);
x=func(x,2,0,arr);
printf("MOEDAS:\n");
arr="moeda";
x=func(x,1,0,arr);
//mod
x=y*100;
x=func(x,50,1,arr);
x=func(x,25,1,arr);
x=func(x,10,1,arr);
x=func(x,5,1,arr);
x=func(x,1,1,arr);
return 0;
}
problem will found in:
https://www.urionlinejudge.com.br/judge/en/problems/view/1021
If you just want to round off to two decimal points you could try something like:
a = ((int) (a*100))/100.0;
The value have only 2 decimal places is a matter of displaying it, so you just need to print the number of decimal places you are interested in, like
float value = 123.123456;
printf("%.2f\n", value);
if you want to dynamicaly specify that number, you can use
float value = 123.123456;
int decimals = 2;
printf("%.*f\n", decimals, value);
If you want to store the value as a string then use sprintf() or better snprintf().
And taking the input with only two decimals does not make sense anyway because the output is what should be filtered instead of the input, note that after all you will ignore the extra decimals inserted by the user.
Also, note that floating point numbers cannot store exact numbers, so even i you leave only two decimal places by doing something like
float value = ((int)(100.0 * 123.1234156)) / 100.0
the actual value that is stored might be
123.1200000001
which has more decimal places.
One thing that you could try is
struct RealNumber
{
int integerPart;
int decimalPart;
};
and then handle the input to read them separately, which will be really dificult.

How to calculate this factorial

#include <stdio.h>
int main(){
int n, v;
printf("Please enter a value from 39 to 59: \n");
scanf("%d", &n);
printf("Please enter a value from 3 to 7: \n");
scanf("%d", &v);
}
When I got those values from user, how can I perform this factorial calculation:
n! / ((n-v)! * v!))
I've tried different data types but apparently none can hold the result.
For example: n = 49, v=6. The result is: 13,983,816, but how can I go about getting it?
You're best bet is to ditch the naive factorial implementations, usually based on recursion, and switch to one that returns the natural log of gamma function.
The gamma function is related to factorial: gamma(n) = (n-1)!
Best of all is natural log of gamma, because you can rewrite that expression like this:
ln(n!/(n-v)!v!) = ln(n!) - ln((n-v)!) - ln(v!)
But
(n-v)! = gamma(n-v+1)
n! = gamma(n+1)
v! = gamma(v+1)
So
ln(n!/(n-v)!v!) = lngamma(n+1) - lngamma(n-v+1) - lngamma(v+1)
You can find an implemenation for lngamma in Numerical Recipes.
lngamma returns a double, so it'll fit even for larger values.
It should go without saying that you'll take exp() of both sides to get the original expression you want back.
#duffymo idea looked like too much fun to ignore: use lgamma() from <math.h>.
Results past maybe x=1e15, start to lose the trailing significant digits.. Still fun to be able to get 1000000.0!.
void factorial_expo(double x, double *significand, double *expo) {
double y = lgamma(x+1);
const static double ln10 = 2.3025850929940456840179914546844;
y /= ln10;
double ipart;
double fpart = modf(y, &ipart);
if (significand) *significand = pow(10.0, fpart);
if (expo) *expo = ipart;
}
void facttest(double x) {
printf("%.1f! = ", x);
double significand, expo;
factorial_expo(x, &significand, &expo);
int digits = expo > 15 ? 15 : expo;
if (digits < 1) digits++;
printf("%.*fe%.0f\n", digits, significand, expo);
}
int main(void) {
facttest(0.0);
facttest(1.0);
facttest(2.0);
facttest(6.0);
facttest(10.0);
facttest(69.0);
facttest(1000000.0);
return 0;
}
0.0! = 1.0e0
1.0! = 1.0e0
2.0! = 2.0e0
6.0! = 7.20e2
10.0! = 3.628800e6
69.0! = 1.711224524281441e98
1000000.0! = 8.263931668544735e5565708
In a comment, you've finally said that you don't need exact results.
Just use floating-point. The largest intermediate result you'll need to handle is 59!, which is about 1.3868e80; type double is more than big enough to hold that value.
Write a function like:
double factorial(int n);
(I presume you know how to implement it) and use that.
If you're going to be doing a lot of these calculations, you might want to cache the results by storing them in an array. If you define an array like:
double fact[60];
then you can store the value of N! in fact[N] for N from 0 to 59 -- and you can fill the entire array in about the time it would take to compute 59! just once. Otherwise, you'll be doing several dozen floating-point multiplications and divisions on each calculation -- which is trivial if you do it once, but could be significant if you do it, say, thousands or millions of times.
If you needed exact results, you could use an extended integer library like GNU MP, as others have suggested. Or you could use a language (like Python, for example) that has built-in support for arbitrary-length integers.
Or you could probably perform the multiplications and divisions in an order that avoids overflow; I don't know exactly how to do that, but since n! / ((n-v)! * v!)) is a common formula I strongly suspect that work has already been done.
You can't work with such long numbers as 59! in simple way.
However you can use special C libraries which are working with long numbers bigger than 8 bytes, for example GMP

Inexplicable computational error

I am writing a program that reads wavelength and intensity data from separate signal and background files (so each file is comprised of a number of pairs of wavelength and intensity). As you can see, I do this by creating a structure, and then assigning the values to the proper elements in the structure using fscanf in a loop. Once the data is read in, the program is supposed to plot it on the interval where the recorded wavelengths in each file overlap, that is, the common range of wavelengths. The wavelengths align perfectly where this overlap exist and are known to be spaced at a constant difference. Thus, my way of discerning which elements of the structure array were applicable was to determine which of the two files' minimum wavelength was higher, and maximum wavelength was lower. Then, for the file that had the lower minimum and higher maximum, I would find the difference between this and the higher minimum/lower maximum, and then divide it by the constant step to determine how many elements to offset. This works, except when the math is done, the program returns a wrong answer that is completely inexplicable.
In the code below, I define the constant step as lambdastep by calculating the difference between wavelengths of one element and the element before it. With my sample data, it is .002, which is confirmed by printf. However, when I run the program and divide by lambdastep, I get an incorrect answer. When I run the program dividing by .002, I get the correct answer. Why is this case? There is no explanation I can think of.
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include "plots.h"
struct spectrum{
double lambda;
double intensity;
};
main(){
double a=0,b=0,c=0,d=0,lambdastep,smin,smax,bmin,bmax,tmin,tmax,sintmin,bintmin,tintmin,sintmax,bintmax,tintmax,ymin,ymax;
int ns,nb,nt,i=0,sminel,smaxel,bminel,bmaxel,tminel,tmaxel;
double min(struct spectrum *a,int,int);
double max(struct spectrum *a,int,int);
FILE *Input;
Input = fopen("sig.dat","r");
FILE *InputII;
InputII = fopen("bck.dat","r");
fscanf(Input,"%d",&ns);
fscanf(InputII,"%d",&nb);
struct spectrum signal[ns];
struct spectrum background[nb];
struct spectrum *s = &signal[0];
struct spectrum *ba = &background[0];
s = malloc(ns*sizeof(struct spectrum));
ba = malloc(nb*sizeof(struct spectrum));
while( fscanf(Input,"%lf%lf",&a,&b) != EOF){
signal[i].lambda = a;
signal[i].intensity = b;
i++;
}
i = 0;
while( fscanf(InputII,"%lf%lf",&c,&d) != EOF){
background[i].lambda = c;
background[i].intensity = d;
i++;
}
for (i=0; i < ns ;i++){
printf("%.7lf %.7lf\n", signal[i].lambda,signal[i].intensity);
}
printf("\n");
for (i=0; i < nb ;i++){
printf("%.7lf %.7lf\n", background[i].lambda,background[i].intensity);
}
lambdastep = signal[1].lambda - signal[0].lambda; //this is where I define lambdastep as the interval between two measurements
smin = signal[0].lambda;
smax = signal[ns-1].lambda;
bmin = background[0].lambda;
bmax = background[nb-1].lambda;
if (smin > bmin)
tmin = smin;
else
tmin = bmin;
if (smax > bmax)
tmax = bmax;
else
tmax = smax;
printf("%lf %lf %lf %lf %lf %lf %lf\n",lambdastep,smin,smax,bmin,bmax,tmin,tmax); //here is where I confirm that it is .002, which is the expected value
sminel = (tmin-smin)/(lambdastep); //sminel should be 27, but it returns 26 when lamdastep is used. it works right when .002 is directly entered , but not with lambdastep, even though i already confirmed they are exactly the same. why?
sminel is an integer, so (tmin-smin)/lambdastep will be casted to an integer when the calculation concludes.
A very slight difference in lambdastep could be the difference between getting e.g. 27.00001 and 26.99999; the latter truncates down to 26 when cast to an int.
Try using floor, ceil, or round to get better control over the rounding of the returned value.
It almost certainly has to do with the inherent imprecision of floating-point calculations. Trying printing out lambdastep to many significant digits -- I bet you'll find that its exact value is slightly larger than you think it is.
With my sample data, it is .002, which is confirmed by printf.
Try printing out (lambdastep == .002).

Resources