dynamically set decimal separator in number/string using c programming - c

i am facing problem while placing decimal point in my input string.please refer my code for better understanding.
Description:The field shall be eight (8) digits in width, right-aligned, zero-filled. Left most digit denotes the number of positions the decimal separator shall be move from the right.
Expected result should be like this :
example 1: 71234567
output 0.1234567
example 2 : 31234567
output : 1234.567
But when i run my code with above example i am getting below output.
output 1 : 0.123457
output 2 : 1234.567000
It should not need to append the zeroes in right hand side.why this is happening.could anyone please tell me.
Attached my code snippet:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
int main()
{
unsigned char str[8] = "31234567";
int num = atoi(str); //Convert string to int
printf("num = %d\n",num);
int FirstDigit = num;
num = num % (unsigned long)pow(10.0, (double)floor(log10(num)));
printf("After removing 1st digit from number = %d\n",num);
while(FirstDigit>=10)
{
FirstDigit = FirstDigit/10;
}
printf("Decimal position stored in FirstDigit = %d\n",FirstDigit);
printf("Final value = %f",num/pow(10,FirstDigit));
return 0;
}

For default printf gives 6 significant digits, if precision is not specified.
https://man7.org/linux/man-pages/man3/printf.3.html
g, G The double argument is converted in style f or e (or F or
E for G conversions). The precision specifies the number
of significant digits. If the precision is missing, 6
digits are given; if the precision is zero, it is treated
as 1. Style e is used if the exponent from its conversion
is less than -4 or greater than or equal to the precision.
Trailing zeros are removed from the fractional part of the
result; a decimal point appears only if it is followed by
at least one digit.
In your case you are trying to print the number 0.1234567 but in that number there are 7 significant digits. So printf rounds that number to 0.123457. You can specify precision like this.
printf("Final value = %.7f",num/pow(10,FirstDigit)); // (%.7f)
But you also want to get rid of the trailing zeros. For this you can use it like this.
printf("Final value = %.10g",num/pow(10,FirstDigit)); // (%.10g)
I specified precison as 10 because you are using int. Hence int can have at most 10 digits.

Related

Why does my computer arbitrarily change the decimal digits at the end of a float number when that number is the actual parameter of a function?

I was trying to satisfy this question: Write a function print_dig_float(float f) which prints the value of each digit of a floating point number f. For example, if f is 2345.1234 the print_dig_float(f) will print integer values of digits 2, 3, 4, 5, 1, 2, 3, and 4 in succession.
What I did is: given a number with some decimals, I try to move the digits to the left (Ex: 3.45 -> 345) by multiplying it with 10. After that, I store each digit in an array by taking the remainder and put it in an element. Then, I print them out.
So my program looks like this:
#include <stdio.h>
void print_dig_float(float f);
int main(int argc, char const *argv[]) {
print_dig_float(23432.214122);
return 0;
}
void print_dig_float(float f) {
printf("%f\n", f);
int i = 0, arr[50], conv;
//move digits to the left
do {
f = f * 10;
conv = f;
printf("%i\n", conv);
} while (conv % 10 != 0);
conv = f / 10;
//store digits in an array
while (conv > 1) {
arr[i] = conv % 10;
conv = conv / 10;
i++;
}
for (int j = i - 1; j >= 0; j--) {
printf("%i ", arr[j]);
}
printf("\n");
}
When I tested it with the number: 23432.214122, this is what I get (according to Linux terminal):
23432.214844
234322
2343221
23432216
234322160
2 3 4 3 2 2 1 6
The problem is that, as you can see above, the computer arbitrarily changes the decimal digits at the end of the number even before I do anything with it. I don't know if this is my fault or the computer's fault for this problem.
Per C 2018 5.2.4.2.2, a floating-point number is represented with a sign, a fixed base to some exponent, and a numeral formed of digits in that base. Most commonly, two is used as the base.
When the base is two, 23432.214122 cannot be represented in floating-point, because every representable number is necessarily some integer multiple of a power of the base (possible a negative power). 23432.214122 is not a multiple of ½, ¼, ⅛, 1/24, 1/25, or any other power of two.
When 23432.214122 is used in source code, it is converted to a value that is representable. In good C implementations, the nearest representable value is used, but the C standard permits either the representable value that is the nearest larger or nearest smaller value to be used. Other than this, the digits that appear are not arbitrary; they are a consequence of the mathematics.
When IEEE-754 binary32 is used for float, the representable value nearest to 23432.214122 is exactly 23432.21484375.
Because, when a C implementation uses base two for floating-point numbers, floating-point numbers have binary digits and do not have decimal digits. It is generally not meaningful to attempt to extract decimal digits from a thing that does not have decimal digits. It is possible to determine the decimal digits that were in an original numeral up to some limit affected by the floating-point format. However, “23432.214122” has too many digits to do this with a 32-bit floating-point type. With a 64-bit type, as is commonly used for double, you could recover the original digits providing you knew how many decimal digits there were to start with. It is not generally possible to recover the original numeral without that information—as you have seen the trailing digits will be different, and there is no indication in the floating-point number itself of where the differences start.

How to set the level of precision for the decimal expansion of a rational number

I'm trying to print out the decimal expansion of a rational number in C. The problem I have is that when I divide the numerator by the denominator I lose precision. C rounds up the repeating part when I don't want it to.
For example, 1562/4995 = 0.3127127127... but in my program I get 1562/4995 = 0.312713. As you can see a part of the number that I need has been lost.
Is there a way to specify C to preserve a higher level of decimal precision?
I have tried to declare the result as a double, long double and float. I also tried to split the expansion into 2 integers seperated by a '.'
However both methods haven't been successful.
int main() {
int numerator, denominator;
numerator = 1562;
denominator = 4995;
double result;
result = (double) numerator / (double) denominator;
printf("%f\n", result);
return 0;
}
I expected the output to be 1562/4995 = 0.3127127127... but the actual output is 1562/4995 = 0.312713
The %f format specifier to printf shows 6 digits after the decimal point by default. If you want to show more digits, use a precision specifier:
printf("%.10f\n", result);
Also, the double type can only accurately store roughly 16 decimal digits of precision.
You need to change your output format, like this:
printf("%.10lf\n", result);
Note two things:
The value after the . specifies the decimal precision required (10 decimal places, here).
Note that I have added an l before the f to explicitly state that the argument is a double rather than a (single-precision) float.
EDIT: Note that, for the printf function, it is not strictly necessary to include the l modifier. However, when you come to use the 'corresponding' scanf function for input, it's absence will generate a warning and (probably) undefined behaviour:
scanf("%f", &result); // Not correct
scanf("%lf", &result); // Correct
If printing is all you want to do, you can do this with the same long division you were taught in elementary school:
#include <stdio.h>
/* Print the decimal representation of N/D with up to
P digits after the decimal point.
*/
#define P 60
static void PrintDecimal(unsigned N, unsigned D)
{
// Print the integer portion.
printf("%u.", N/D);
// Take the remainder.
N %= D;
for (int i = 0; i < P && N; ++i)
{
// Move to next digit position and print next digit.
N *= 10;
printf("%u", N/D);
// Take the remainder.
N %= D;
}
}
int main(void)
{
PrintDecimal(1562, 4995);
putchar('\n');
}

Recursive function to convert between number bases fails at certain numbers

I'm trying to a create an algorithm that can convert base 10 numbers into base n numbers, where n is at most 10. However, for some weird reason the following algorithm in C fails at certain critical points for each base. For example, for base 2 and base 3 conversions, all numbers up to and including 1023 and 52,487 work, respectively, but numbers beyond that produce some weird negative result. I can't figure out why this is happening; can anyone help me?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int returnint;
int baseconvert(int number,int base) {
if(number == 0 || base == 10) {
return returnint;
}
returnint = (number % base) + (10 * baseconvert(number / base, base));
return returnint;
}
int main() {
fprintf(stdout,"%d\n",baseconvert(1023,2));
fprintf(stdout,"%d\n",baseconvert(52487,3));
}
EDIT:
Here is the printed result of the above print statements, if that's helpful:
1410065408
-2094967296
Your algorithm is very limited in the range of numbers vs. bases. The smaller the base is the more digits are needed to represent it. And since you store the result in decimal form, you'll waste your available data range very quickly. There is no fundamental data type that can hold the results for all the possible inputs. E.g., maximal 31-bit decimal number (normal integer, dropping the sign bit) will result in 31-digit output!
You have several options to cope with this:
Allocate a stack large enough and push the digits into it. Upon completion, print the stack contents.
Print the digits immediately without saving, this will eliminate the need to allocate anything.
E.g.:
#include <stdio.h>
void baseconvert(int number,int base)
{
if(number > 0)
{
int digit = (number % base);
baseconvert(number / base, base);
printf("%d",digit);
}
else
{
printf("\n");
}
}
int main()
{
baseconvert(1023,2);
baseconvert(52487,3);
}
It appears that the integer value is overflowing. For example, the decimal value 1023 in base two is 1111111111. If it is a 4 byte integer, then it will overflow when trying to "add" one more digit (the max signed integer in this case being 2147483647).
Since it appears your goal is to display a number in a different base, it might make more sense to store the digits in a character array.
On all processors that I know of, integers are already stored in binary form; this implies base 2. This value can be displayed in whatever base you desire, with some work on your part. printf() and friends allow you to easily print in base 10 (%d) and base 16 (%x). It is not difficult to imagine a method that would convert a binary (base 2) integer value into a character representation in base n.
I seriously doubt that you really intend to change the actual value of the integer, as you are doing. Like #ThoAppelsin said above, the number of apples in the bag stays the same, regardless of which base you choose for display.
By simply creating a method that represents (with digits) the integer in any base, you will also solve your overflow problem!
Your result is overflowing the integer range. Try using strings instead. This is the pseudocode which relies on strings to represent numbers and it can convert numbers from any base to any other base between 2 and 36 inclusive (using digits and upper case letters):
function ConvertNumber(number, b, d)
begin
newNumber = ""
while number <> "0"
begin
number = Divide(number, b, d, out remainder)
newDigit = ValueToDigit(remainder)
newNumber = Concatenate(newDigit, newNumber)
end
if newNumber ="" then
newNumber = "0"
end
function Divide(number, base, divisor, out remainder)
begin
remainder = 0
result = ""
for i = 0 to Length(number) - 1
begin
digitValue = DigitToValue(number[i])
remainder = base * remainder + digitValue
newDigitValue = remainder / divisor -- integer division
remainder = remainder mod divisor
if newDigitValue > 0 OR result <> "" then
newDigit = ValueToDigit(newDigitValue)
result = Concatenate(result, newDigit)
end
if result = "" then
result = "0"
return result
end
You can find the whole math and implementation in this article: Converting Number Bases.

Floating point formatting till specified number

The following is a sample prog
#include<stdio.h>
#include<math.h>
main()
{
int x;
scanf("%d",&x);
printf("%.2f\n",(1/pow(2,x)));
}
Here I give .2f for floating point formatting. We can also give respective .3f or .5f etc according to requirement.
Suppose we do not know till what decimal after the '.' it is to be printed. I want to give something like a value n through input, so that it prints decimals till the n.
like .nf if n = 5 and x =1, it prints 0.50000 and for n = 3 it should print 0.500
How do I achieve this?
You can specify the desired precision as a variable:
int n = 5;
printf("%.*f\n", n, (1.0/pow(2,x))); /* equivalent to %.5f */
Quoting from man 3 printf:
An optional precision, in the form of a period ('.') followed by an
optional decimal digit string. Instead of a decimal digit string one
may write "*" or "*m$" (for some decimal integer m) to specify that the
precision is given in the next argument, or in the m-th argument,
respectively, which must be of type int.

Homework about bit sequence in C

I have a homework. The question is:
Write a function that takes as parameter a single integer, int input, and returns an unsigned character
such that:
a- if input is negative or larger than 11,111,111 or contains a digit that is not 0 or 1; then the function will
print an error message (such as “invalid input”) and return 0,
b- otherwise; the function will assume that the base-10 value of input represents a bit sequence and return the magnitude-only bit model correspondent of this sequence.
For Example: If input is 1011, return value is 11 and If input is 1110, return value is 14
This is my work for a, and I am stuck on b. How can I get bit sequence for given integer input?
int main()
{
int input = 0;
printf("Please type an integer number less than 11,111,111.\n");
scanf("%d",&input);
if(input < 0 || input > 11111111)
{
printf("Invalid Input\n");
system("PAUSE");
return 0;
}
for (int i = 0; i < 8; i++)
{
int writtenInput = input;
int single_digit = writtenInput%10;
if(single_digit == 0 || single_digit == 1)
{
writtenInput /= 10;
}
else
{
printf("Your digit contains a number that does not 0 or 1. it is invalid input\n");
system("PAUSE");
return 0;
}
}
printf("Written integer is %d\n",input);
system("PAUSE");
return 0;
}
The bit that you are missing is the base conversion. To interpret a number in base B, what you need to do is multiply digit N times B^N (assuming that you start counting digits from the least significative). For example, in base 16, A108 = (10)*16^3 + 1*16^2 + 0*16^1 + 8*16^0. Where in your base is 2 (binary).
Alternatively, you can avoid the exponentiation if you rewrite the expression as:
hex A008 = ((((10*16) + 1)*16 +0)*16 + 8
Which would be simpler if your input was stated in terms of an array of possibly unknown length as it is easily convertible into a loop of only additions and multiplications.
In the particular case of binary, you can use another direct solution, for each digit that is non-zero, set the corresponding bit in an integer type large enough (in your case, unsigned char suffices), and the value of the variable at the end of the loop will be the result of the conversion.
First off, the existing part of your code needs work. It doesn't report non-binary digits correctly. The question is "Are there any digits that are neither 0 nor 1". To answer this question in the negative, you need to check every single digit. Your code can terminate early. I also suggest renaming the function to something that clearly tells you what it does. For example haveNonBinaryDigit. The term check doesn't tell you what you should expect on the return value.
As for the second part, read up on the binary representation. It is fairly similar to decimal, except that instead of each digit being weighted by 1, 10, 100, .., 10^x, they are weighted by 1, 2, 4, ..., 2^n. Also the digits can only have values 0 and 1.
Your current code has a problem: it will terminate as soon as it finds one single binary bit (at the end) and call the entire integer correct.
I would take a different approach to this problem. What you want to do is get your hands on every single digit from the integer seperately. You made a good start in doing so by using modulo. Say you had this code:
for (int i = 0; i < 8; i++)
{
char single_digit = input%10;
input /= 10;
}
This makes it easy to start working with the digits. You would be checking 8 bits because that seems to be the maximum allowed (11,111,111). Check if each digit is either 0 or 1. Then you can start pushing it in to an unsigned character using bitwise operations. Shift every digit to the left by i, then use a bitwise OR.

Resources