How to round float numbers in text in C? - c

So I have this text
today average human lifespan in Western countries is approaching and exceeding 80 years.
1 Japan 82.6 123 19
2 Hong Kong 82.2 234 411
3 Iceland 81.8 345 26
4 Switzerland 81.7 456 7
5 Australia 81.2 567 500
...
80 Lithuania 73.0 800 2
...
194 Swaziland 39.6 142 212
195 133714 18.0 133 998
196 100110011 10.0 667 87351
I need to round the float numbers in this text to whole numbers. I've searched a lot of forums but I cannot seem to find what I need.
This text is given in a .txt file. My task: "Round real number(that have decimals) to whole numbers. The corrected text should be in a new .txt" That's it.

scanf and sscanf are your best friend to extract anything of a string.
floor is use full to suppress decimal on a float. Then can be used to round it (to use it include math.h)...
The format string describes the expected format.The function return the number of parameters found.
Sample:
Initialization
int id = -1;
char country[160]; /* /!\ Warning country name length shall be fewer than 160 */
/* Scanf don't care of this array parameter length. If it is too short */
/* It will erase following memory... */
/* That is why scanf are often disparaging */
float percent = 0.0;
char a_number_as_string[10];
int other_number = -1;
char* Switzerland = "4 Switzerland 81.7654321 456 7";
effectif code
int ret = sscanf(Switzerland, "%d %s %f %s %d", &id, country,
&percent, a_number_as_string, &other_number);
if(ret == 5) {
printf("~~ id: %d\n\tcountry: %s\n\tpercent: %.2f\n\tand : "
"(%s, %d)\n", id, country, percent, a_number_as_string,
other_number);
/////// ROUND
printf("*** round");
printf("\twith printf %%.1f = %.1f\n", percent);
printf("\twith printf %%.2f = %.2f\n", percent);
printf("\twith printf %%.3f = %.3f\n", percent);
printf("\twith printf %%.4f = %.4f\n", percent);
printf("*** With floor (included in math.h)\n");
printf("\t1 decimal: %f\n", floor(percent*10)/10);
printf("\t2 decimal: %f\n", floor(percent*100)/100);
printf("\t3 decimal: %f\n", floor(percent*1000)/1000);
printf("\t4 decimal: %f\n", floor(percent*10000)/10000);
} else {
printf("--> ret = %d", ret);
}
output
~~ id: 4
country: Switzerland
percent: 81.70
and : (456, 7)
*** round
with printf %.1f = 81.8
with printf %.2f = 81.77
with printf %.3f = 81.765
with printf %.4f = 81.7654
*** With floor (included in math.h)
1 decimal: 81.700000
2 decimal: 81.760000
3 decimal: 81.765000
4 decimal: 81.765400
This function are describe in Unix, OSX, Unix terminal man pages:
man scanf
man sscanf
man floor
Or you can find it on several copies of this manages on the web for example
scanf
sscanf
floor

here is the program I have already tested it for a single line of input string:-
// LINK - http://stackoverflow.com/questions/40317323/how-to-extract-float-numbers-from-text-in-c#40317323
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
int main()
{
char s[100];
int i,j;
double sum=0.0,frac=0.0;
gets(s); // delimited by '\n' and not by ' '
for( i=0;s[i]!='\0';i++) // for finding index value of decimal point(.)
{
if(s[i]=='.')
break;
}
for(;s[i]!=' ';i--); // for changing key index value to the index value of the first space character(' ') before the decimal point(.)
i++;
for(i;s[i]!='.';i++)
{
sum=sum*10+(s[i]-48); // For extracting integer part
}
i++;
for(i,j=1;s[i]!=' ';i++,j++)
{
frac=frac+(s[i]-48)/pow(10,j); // For extracting fractional part
}
printf("\n\n%lf",sum+frac); // final answer integer part+decimal part
return 0;
}
Explanation:-
okay so what I did is:-
Since scanf() is automatically delimited by space I used gets() which is delimited by new line;
Then we know that there will be a decimal point(.) for floating number in the string, so we find the index value(say key) of the decimal point in the array.
Once we have found the decimal point we know there will only be numbers between the decimal point and the space character after the country name so now we find the index value of that space(key).
Now from that key value we again first move to the decimal point(.) character index while calculating the integer part.Calculated using ASCII value i.e. ASCII value of character Zero(0) is 48 and character Nine(9) is 57 hence subtracting 48 from every character and extracting the value.
Again from the Decimal point(.) to the next space character in the string is part of the floating number and after decimal the numbers follow the weight 10^(-1),10^(-2),10^(-3)...and so on hence the temporary variable and the power() function.Thus we, successfully calculated the fractional part also.
Finally, I just added the Integer and the fractional parts within the printf().
Try, using printf() with all the variables in each of the for loops for better understanding, kinda like dry-run.

You can parse all the values from the string using regex in c#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string[] input = {
"today average human lifespan in Western countries is approaching and exceeding 80 years.",
"1 Japan 82.6 123 19",
"2 Hong Kong 82.2 234 411",
"3 Iceland 81.8 345 26",
"4 Switzerland 81.7 456 7",
"5 Australia 81.2 567 500",
"80 Lithuania 73.0 800 2",
"194 Swaziland 39.6 142 212",
"195 133714 18.0 133 998",
"196 100110011 10.0 667 87351"
};
string pattern = #"(?'index'\d+)\s+(?'country'.*)\s+(?'float'[^ ]+)\s+(?'num1'\d+)\s+(?'num2'\d+)$";
for (int i = 1; i < input.Length; i++)
{
Match match = Regex.Match(input[i], pattern);
Console.WriteLine("index : '{0}', country : '{1}', float : '{2}', num1 : '{3}', num2 : '{4}'",
match.Groups["index"],
match.Groups["country"],
match.Groups["float"],
match.Groups["num1"],
match.Groups["num2"]
);
}
Console.ReadLine();
}
}
}

Related

How can fscanf(), in C, be used to read a .gro file?

I am trying to read the following gro file via a C code.
FJP in Pol Water in water t= 0.00000 step= 0
16
1FJP P 1 5.346 7.418 0.319
2FJP P 2 5.151 7.405 0.499
3FJP P 3 5.260 7.178 0.428
4FJP P 4 5.159 6.961 0.342
5FJP P 5 5.355 6.909 0.220
6FJP P 6 5.169 6.824 0.043
7FJP P 7 5.068 6.669 11.454
8FJP P 8 4.919 6.861 11.482
9FJP P 9 4.835 7.075 11.364
10FJP P 10 4.738 6.987 11.197
11FJP P 11 4.847 7.115 10.993
12FJP P 12 4.642 7.126 10.870
13FJP P 13 4.680 6.940 10.674
14FJP P 14 4.521 7.052 10.545
15FJP P 15 4.321 6.973 10.513
16FJP P 16 4.315 6.728 10.516
11.56681 11.56681 11.56681
My code is:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[])
{
char input_file[]="file.gro";
FILE *input;
char *myfile=malloc(sizeof(char)*80);
sprintf(myfile,"%s",input_file); //the .gro file being read in
input=fopen(myfile,"r");
double dummy1,dummy6,dummy7,dummy8,dummy9,dummy10,dummy11;
int dummy2,dummy3,dummy4,dummy5;
int lines=0;
while (fscanf(input,"FJP in Pol Water in water t= %lf step= %d",&dummy1,&dummy2)==2
||fscanf(input," %d\n",&dummy3)==1
||fscanf(input," %dFJP P %d %lf %lf %lf\n",
&dummy4,&dummy5,&dummy6,&dummy7,&dummy8)==5
||fscanf(input," %lf %lf %lf\n",&dummy9,&dummy10,&dummy11)==3)
{
printf("%lf %d\n",dummy1,dummy2);
printf("%d\n",dummy3);
printf("%d %d\n",dummy4,dummy5);
printf("%lf %lf %lf\n",dummy6,dummy7,dummy8);
printf("%lf %lf %lf\n",dummy9,dummy10,dummy11);
lines=lines+1;
}
printf("lines=%d\n",lines);
fclose(input);
}
The problem is the values printed by the various dummy variables do not match what is in the file. Also, the number of lines being read is 3 as opposed to 19, which matches the file. I am not certain what is incorrect about my fscanf() statements to read this file. Any help for this problem would be much appreciated.
Your main problem is that you are assuming scanf is better than it is.
Scanf will read and parse as many arguments as it can, and then give up. It does not rewind to the start of the scanf. Also it treats spaces and newlines (and tabs) as simply "skip all whitespace"
So the line printf("%d\n",dummy3) will try to parse the main lines, eg 1FJP
It will read the digit 1 OK into dummy3, but then get stuck because P != a whitespace.
All the other rules will then get stuck, because none of them expect a P or any string first.
If you want to do it this way, you will just have to apply the scanf statements more intelligently as and when they are expected.
The problem is that you try to read and match the header repeatedly, before each line read (in the while loop.) you should read the head once, then read the lines. You also only need to skip any given piece of whitespace once. So you end up with code like:
if (fscanf(input,"FJP in Pol Water in water t=%lf step=%d%d", &dummy1, &dummy2, &dummy3) != 3) {
fprintf(stderr, "Invalid header\n");
exit(1); }
while (fscanf(input,"%dFJP P%d%lf%lf%lf", &dummy4, &dummy5, &dummy6, &dummy7, &dummy8) == 5) {
... read a line of the table

Q: About reading data files using fscanf()

Am using Turbo C in a DOS emulator (Dosbox). In the following lines, I am trying to read integer and float data but only get the first (int) field. Have found much Q & A on the subject of reading files using fscanf() and, specifically, with space-delimited data but relevant info was scant or missing (mostly from the questions). Here is code demonstrating the problem:
#include <stdio.h>
int index;
float rtime, volts;
char infilename[10];
int *pti;
float *ptx;
float *pty;
FILE *infp;
void main(void)
{
infp = fopen("data1", "r");
pti = &index;
ptx = &rtime;
pty = &volts;
fscanf(infp, "%d %6.3f %6.3f", &index, &rtime, &volts);
printf("%3d %6.3f %6.3f\n", index, rtime, volts);
}
Here is the first line from the data file:
37 261.100 0.996
printf gives the following output:
37 0.000 0.000
Any obvious goofs? thx
The format %6.3f is incorrect for scanf(). You probably want %f, or possibly %7f. You cannot specify the number of decimals in a scanf() format.

values changed by fscanf and fprintf for text file in C program [duplicate]

This question already has answers here:
What range of numbers can be represented in a 16-, 32- and 64-bit IEEE-754 systems?
(7 answers)
Closed 6 years ago.
I would like to output like "correct output data" from "input data" by below C program. But the result shows that the values are changed like "actual output data". Let me know how to solve it.
input data
-5190.978 -90026.901 158.677 15 90 81 58
-5165.821 -90011.875 152.742 15 90 89 54
-5158.762 -90010.093 148.083 31 80 82 42
correct output data
-5190.978 -90026.901 158.677 90 81 58
-5165.821 -90011.875 152.742 90 89 54
-5158.762 -90010.093 148.083 80 82 42
actual output data
-5190.978 -90026.898 158.677 90 81 58
-5165.821 -90011.875 152.742 90 89 54
-5158.762 -90010.094 148.083 80 82 42
/***************************************************************************:::
xyz(ref)rgb2xyzrgb
19/08/2016
ver1.1 2009/3/7
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int main(int argc,char *argv[])
{
FILE *fpr,*fpw;
int ref,r,g,b;
float x,y,z;
float n_x,n_y,n_z;
/*****************************************************
2.command line arguments processing
*******************************************************/
if(argc!=3)
{
fprintf(stderr,"Usage: %s (1)input_org.txt\n(2)write_xyz FILENAME\n",argv[0]);
exit(1);
}
printf("OPEN FILE NAME:%s\n",argv[1]);
/**********************************************************************************
**********************************************************************************
4. FILE OPEN + Binary File Input
**********************************************************************************
*************************************************************************************/
// open input file
if((fpr=fopen(argv[1],"rt"))==NULL)
{
printf("file cannot be opened。\n");
exit(1);
}
//write file
if((fpw=fopen(argv[2],"wt"))==NULL)
{
fprintf(stderr,"DSM by GSI data.raw\n");
exit(1);
}
while (fscanf(fpr,"%f %f %f %d %d %d %d", &x,&y,&z,&ref,&r,&g,&b) != EOF)
{
//printf("%.3f %.3f %.3f %d %d %d\n",x,y,z,r,g,b);
n_x = roundf(x * 1000) / 1000;
n_y = roundf(y * 1000) / 1000;
n_z = roundf(z * 1000) / 1000;
//printf("%.3f %.3f %.3f %d %d %d\n",n_x,n_y,n_z,r,g,b);
fprintf(fpw,"%.3f %.3f %.3f %d %d %d\n",n_x,n_y,n_z,r,g,b);
//printf("x:%f y:%f z:%f\n", x,y,z);
}
fclose(fpr);
fclose(fpw);
}
Instead of -90026.901 computer stores the nearest number that fits the precision. It's 90026.898. Remember that numbers are stored in binary on computers and 901/1000 doesn't have finite binary form. For this reason, some of the precision will be cut.
It would be the same if you tried to print 1/3. It won't print all the digits, but you actually expect it as you're used to decimal system. In binary system, some of the fractions that have finite decimal form won't have one.
The solution? Always try to enlarge macheps which is the arithmetic precision. The easiest would be to use double instead of float. It still doesn't give 100% but it's more probable that will work.
The topic is known as scientific calculation and is pain in a** for programmers.

Why is fscanf changing values of structure without explicitly being told to?

I am trying to read a text file into a structure in c, but on the last iteration of my fscanf() loop, it changes both the numbers and text stored in the first and some of the second parts of my structure.
Debugging has revealed that this behaviour is caused by the while fscanf() loop. Although changing the size of the strings input prevented the numbers being changed, the string on the first line PMs.Party[0] still changed from = Labour to r. Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
void PartyPwr( int Runs, int Time[12], char Prty[12][15]);
struct Data
{
char *Name[12][15];
int StrtMnth[12];
int StrtYr[12];
int EndMnth[12];
int EndYr[12];
char Party[12][15]; // if this is 13 20 it runs without numbers changing.
int TimePwr[12];
};
int main(void)
{
int Max=0;
int i=0;
FILE *PriMins;
struct Data PMs;
if ((PriMins=fopen("PM.txt", "r")) == NULL)
{
printf("Error: PM.txt cannot be read.");
system("pause");
return(1);
}
while(fscanf(PriMins, "%s %d %d %d %d %s", &PMs.Name[Max], &PMs.StrtMnth[Max], &PMs.StrtYr[Max], &PMs.EndMnth[Max], &PMs.EndYr[Max], &PMs.Party[Max]) > 0)
{
PMs.TimePwr[Max]=((PMs.EndMnth[Max] +(PMs.EndYr[Max]*12)) - (PMs.StrtMnth[Max] + (PMs.StrtYr[Max]*12)));
printf("%s %d Total term %d\n",PMs.Name[Max], PMs.EndMnth[Max],PMs.TimePwr[Max]);
printf("Max val, %d bug check %d, %d, Party %s\n",Max, PMs.TimePwr[0], PMs.TimePwr[1], PMs.Party[0]);
Max++;
}
//PartyPwr(Max, PMs.TimePwr, PMs.Party);
//printf("%d, %d", PMs.TimePwr[0], PMs.TimePwr[1]);
fclose(PriMins);
system("pause");
return(0);
}
void PartyPwr( int Runs , int Time[12], char Prty[12][15])
int i=0;
int LabPwr=0;
int ConPwr=0;
for (i=0;i<Runs;i++)
{
printf("%s\n", Prty[i]);
if (strcmp(Prty[i],"Labour")==0)
{
LabPwr=(LabPwr+Time[i]);
}
if (strcmp(Prty[i],"Conservative")==0)
{
ConPwr=(ConPwr+Time[i]);
}
if ((strcmp(Prty[i],"Conservative")!=0) && (strcmp(Prty[i],"Labour")!=0))
{
printf("An invalid party was present in the list.");
}
}
printf ("Total Labour time in power: %d\nTotal Conservative time in power: %d\n", LabPwr, ConPwr);
}
This is the text file for the programme.
Attlee 7 1945 10 1951 Labour
Churchill 11 1951 5 1955 Conservative
Eden 6 1955 12 1956 Conservative
Macmillan 1 1957 10 1963 Conservative
Douglas-Home 11 1963 10 1964 Conservative
Wilson 11 1964 5 1970 Labour
Heath 6 1970 2 1974 Conservative
Wilson 3 1974 3 1976 Labour
Callaghan 4 1976 4 1979 Labour
Thatcher 5 1979 11 1990 Conservative
Major 12 1990 4 1997 Conservative
Blair 5 1997 6 2007 Labour
Brown 6 2007 5 2010 Labour
EDIT: I've just discovered if the size of every variable in Data is increased by one, the code runs without any of the issues. I assume this is some kind of overflow?
EDIT 2: Specifically if EndYr is [13] not [12] the problem is eliminated.
The word Conservative is 12 characters, but you must account for the null char '\0' at the end of every C string.
That is why your code works when you use 13 chars array for the Party field.
What you should do
Specify the maximum length of the Party field in the scanf format specifier. For example, if you keep 12 chars array for the party field:
fscanf(PriMins, "%s %d %d %d %d %11s", &PMs.Name[Max], &PMs.StrtMnth[Max], &PMs.StrtYr[Max], &PMs.EndMnth[Max], &PMs.EndYr[Max], &PMs.Party[Max])
You are reading 13 records from the file and have space to store only 12 of them as all you data items are of size 12.If you increase the size by 1 there is enough room for all 13 records
struct Data
{
char Name[13][15];
int StrtMnth[13];
int StrtYr[13];
int EndMnth[13];
int EndYr[13];
char Party[13][15];
int TimePwr[13];
};

Reading text files with strtol in C line by line

OK so I've got this function which finds the average of all numbers in a file:
float averageOfNumbers(FILE *fp_in)
{
int n=0,S=0;
char red[1024];char *ptr;
int p_a_h;
float sr;
while(!feof(fp_in)){
if(fgets(red,1024,fp_in)!=NULL){
ptr =red;
while(p_a_h = strtol(ptr, &ptr, 10)){
if((p_a_h>0&&S>INT_MAX-p_a_h)||(p_a_h<0&&S<INT_MIN-p_a_h)){
printf("OVERFLOW\n");
break;
}
else{
S=p_a_h+S;
n++;}
}
}
}
sr=S/n;
return sr;
}
It works fine when there are only numbers in the file but if it finds anything other than a digit, the program will crash. How can I make it so that the program ignores other symbols. For example here is a text file:
wdadwa 321 1231 das 421124 1 wdasdad 4 1412515
sad14312 yitiyt453534 3554312 sad -2 -53 -12 -231 ##!
#!312 -2 241 -46343 sada 21312 65454
Average should be: 310422
Add an additional check in the if condition.
p_a_h==0 && (strlen(ptr)>1 || (strlen(ptr)==1 && ptr[0]!='0'))
I am making use of the fact that strtol returns 0L if the conversion is invalid(if the string contains non-digit characters). But checking for this alone, also skips if the actual string contains 0. I leave the rest to understand it yourself.

Resources