float.Parse(string) method uses your current culture settings by default. Looks like your CurrentCulture's NumberDecimalSeparator property is , not .
That's why you get FormatException in your "0.54" example.
As a solution, you can use a culture have . as a NumberDecimalSeparator like InvariantCulture as a second parameter in Parse method, or you can .Clone() your CurrentCulture and set it's NumberDecimalSeparator property to .
float number = float.Parse("0.54", CultureInfo.InvariantCulture);
or
var culture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
culture.NumberFormat.NumberDecimalSeparator = ".";
float number = float.Parse("0.54", culture);
Answer from Soner Gönül on Stack OverflowVideos
float.Parse(string) method uses your current culture settings by default. Looks like your CurrentCulture's NumberDecimalSeparator property is , not .
That's why you get FormatException in your "0.54" example.
As a solution, you can use a culture have . as a NumberDecimalSeparator like InvariantCulture as a second parameter in Parse method, or you can .Clone() your CurrentCulture and set it's NumberDecimalSeparator property to .
float number = float.Parse("0.54", CultureInfo.InvariantCulture);
or
var culture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
culture.NumberFormat.NumberDecimalSeparator = ".";
float number = float.Parse("0.54", culture);
It seems your culture uses comma as the decimal separator. Try parsing it with InvariantCulture:
var value = float.Parse(tempLine.Substring(begin, end), CultureInfo.InvariantCulture);
In addition to this, the way you're parsing the lines is more complicated than it should be. You can just split the line instead of trying to deal with indices:
foreach(var str in tempLine.Split())
{
float value = float.Parse(str, CultureInfo.InvariantCulture);
}
It is indeed unfortunate that the C Standard does not provide functions to handle these conversions for a specified locale.
There is no simple portable solution to this problem using standard functions. Converting the strings from the config file to the locale specific alternative is feasible but tricky.
There is a simple work around for the config file. Use the exponent notation without decimals: 123e-3 is portable locale neutral version of 0.123 or 0,123.
POSIX has alternate functions for most standard functions with locale specific behavior, but unfortunately not for strtod() and friends.
Yet both the GNU libc on linux (and alternate libraries such as musl) and the BSD systems support extended POSIX locale functions:
#define _GNU_SOURCE // for linux
#include <stdlib.h>
#ifdef __APPLE__
#include <xlocale.h> // on macOS
#endif
double strtod_l(const char * restrict nptr, char ** restrict endptr,
locale_t loc);
float strtof_l(const char * restrict nptr, char ** restrict endptr,
locale_t loc);
long double strtold_l(const char * restrict nptr, char ** restrict endptr,
locale_t loc);
On macos, it seems you can pass 0 for the loc argument and get the C locale, on linux loc is specified in the header file as non null so you need to create a C locale with newlocale.
Here is an example:
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>
#ifdef __APPLE__
#include <xlocale.h>
#endif
locale_t c_locale;
int main(void) {
const char locale_name[] = "fr_FR.UTF-8";
const char locale_string[] = "0,123";
const char standard_string[] = "0.123";
c_locale = newlocale(LC_ALL_MASK, "C", (locale_t)0);
setlocale(LC_ALL, locale_name);
double x1, x2, y1, y2;
x1 = strtod(locale_string, NULL);
x2 = strtod_l(standard_string, NULL, c_locale);
int s1 = sscanf(locale_string, "%lf", &y1);
int s2 = sscanf_l(standard_string, c_locale, "%lf", &y2);
printf("default locale: %s\n\n", locale_name);
printf("using printf(...):\n");
printf(" strtod(\"%s\", NULL) -> %f\n", locale_string, x1);
printf(" strtod_l(\"%s\", NULL, c_locale) -> %f\n", standard_string, x2);
printf(" sscanf(\"%s\", &y1) -> %d, y1=%f\n", locale_string, s1, y1);
printf(" sscanf_l(\"%s\", c_locale, &y2) -> %d, y2=%f\n", standard_string, s2, y2);
printf("\nusing printf_l(c_locale, ...):\n");
printf_l(c_locale, " strtod(\"%s\", NULL) -> %f\n", locale_string, x1);
printf_l(c_locale, " strtod_l(\"%s\", NULL, c_locale) -> %f\n", standard_string, x2);
printf_l(c_locale, " sscanf(\"%s\", &y1) -> %d, y1=%f\n", locale_string, s1, y1);
printf_l(c_locale, " sscanf_l(\"%s\", c_locale, &y2) -> %d, y2=%f\n", standard_string, s2, y2);
return 0;
}
Output:
default locale: fr_FR.UTF-8
using printf(...):
strtod("0,123", NULL) -> 0,123000
strtod_l("0.123", NULL, c_locale) -> 0,123000
sscanf("0,123", &y1) -> 1, y1=0,123000
sscanf_l("0.123", c_locale, &y2) -> 1, y2=0,123000
using printf_l(c_locale, ...):
strtod("0,123", NULL) -> 0.123000
strtod_l("0.123", NULL, c_locale) -> 0.123000
sscanf("0,123", &y1) -> 1, y1=0.123000
sscanf_l("0.123", c_locale, &y2) -> 1, y2=0.123000
If strtod_l is not available, copying the string and substituting the decimal separator will be required, but here is a list of caveats:
- the source string will be copied to a temporary buffer of sufficient length, at least 300 bytes, possibly more needed.
- the source array can contain arbitrary spacing before the number and arbitrary text after the number and might not be null terminated.
- the
endptrmust be computed to point to the source string, if the prefix was not copied, an adjustment is necessary - swapping
.for,is incorrect: making assumptions regarding the current decimal separator is risky, the appropriate one for the currently selected locale must be retrieved vialocaleconv(), it is the string pointed to by thedecimal_pointmember of thestruct lconv. If this string has more than one character, updating the end pointer is tricky. - if the current locale is changed concurrently in another thread, the behavior is undefined.
A simpler and safer solution is to read the settings at the beginning of the process, before changing the locale. The process starts in the "C" locale. The problem remains if the settings must be updated as snprintf() will use the current locale too.
POSIX-specific
The uselocale function only changes the calling thread's locale. Therefore you can use it temporarily in a wrapper around your formatting functions. However, it is somewhat tedious to use as there is no predefined locale_t value representing the C locale. You have to allocate a new one.
#include <locale.h>
#include <stdio.h>
locale_t C_LOCALE;
int main(void)
{
/*
* Global initialization
*/
C_LOCALE = newlocale(LC_ALL_MASK, "C", (locale_t) 0);
setlocale(LC_ALL, "");
printf("With locale: %g\n", 3.14);
{
/*
* Per thread
*/
locale_t saved_locale;
saved_locale = uselocale(C_LOCALE);
printf("Without locale: %g\n", 3.14);
uselocale(saved_locale);
}
/*
* Could be a global destructor
*/
freelocale(C_LOCALE);
}
Use atof() or strtof()* instead:
printf("float value : %4.8f\n" ,atof(s));
printf("float value : %4.8f\n" ,strtof(s, NULL));
https://cplusplus.com/reference/cstdlib/atof/
https://cplusplus.com/reference/cstdlib/strtof/
atoll()is meant for integers.atof()/strtof()is for floats.
The reason why you only get 4.00 with atoll() is because it stops parsing when it finds the first non-digit.
*Note that strtof() requires C99 or C++11.
Unfortunately, there is no way to do this easily. Every solution has its drawbacks.
Use
atof()orstrtof()directly: this is what most people will tell you to do and it will work most of the time. However, if the program sets a locale or it uses a library that sets the locale (for instance, a graphics library that displays localised menus) and the user has their locale set to a language where the decimal separator is not.(such asfr_FRwhere the separator is,) these functions will stop parsing at the.and you will stil get4.0.Use
atof()orstrtof()but change the locale; it's a matter of callingsetlocale(LC_ALL|~LC_NUMERIC, "");before any call toatof()or the likes. The problem withsetlocaleis that it will be global to the process and you might interfer with the rest of the program. Note that you might query the current locale withsetlocale()and restore it after you're done.Write your own float parsing routine. This might be quite quick if you do not need advanced features such as exponent parsing or hexadecimal floats.
Also, note that the value 4.08 cannot be represented exactly as a float; the actual value you will get is 4.0799999237060546875.
here is what i have so far.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace Algoriths_assessment_2
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Here is the 'Change_128 Document'");
string[] newFile = File.ReadAllLines("Change_128.txt");
Array.Sort(newFile);
for (int i = 0; i < newFile.Length; i += 1)
{
Console.WriteLine(newFile[i]);
}
Console.ReadLine();
}
}}
it works (sort of) it sorts the text document properly but it doesnt take into account negative numbers. this is why i need to convert the string to a float. if someone could help me i would be greateful. (first post, sorry if im wrong)
Thanks for including a test program - that's always valuable!
However, I'm going to change it, to parse a battery of test cases instead of reading from stdin:
#include <stdio.h>
int main(void)
{
static const char *const strings[] = {
/* these should parse fully */
"12",
"12.0",
"08", /* not octal! */
"+12.34",
".34",
"\t \n2.",
"1e0",
"1e+0",
"1e-0",
"1.e4",
".1e-4",
"-5e006",
"-5e+16",
"-.05",
"-.0",
"-1e6",
/* these should parse only the initial part */
"5c5",
"10ee5",
"0x06", /* not hex! */
"--1" ,
"-+1" ,
"1e--4" ,
"-1e.4",
"1e 4",
"1e-g",
"", "foobar", /* both 0 */
" e5", /* also 0 */
"-1e6",
/* overflow/underflow */
"1e500000",
"1e-500000",
"-1e500000",
"-1e-500000",
};
static const int max = sizeof strings / sizeof strings[0];
for (int i = 0; i < max; ++i)
printf("%20s = > %.9g\n", strings[i], extended_atof(strings[i]));
}
(I changed the function name to extended_atof() so as to be safely distinct from the standard library atof().)
Your implementation passes all these tests. Now we can look at refactoring.
Remove duplication
The things that we parse in multiple places are:
- optional sign
+or- - digit sequences
So perhaps we can refactor each of those into a function? Instead of using an integer index into the supplied string, I prefer to just move the string pointer, and eliminate the need for i:
/* return true for positive, false for negative,
and advance `*s` to next position */
static bool parse_sign(const char **s)
{
switch (**s) {
case '-': ++*s; return false;
case '+': ++*s; return true;
default: return true;
}
}
Let's make use of that in the function:
double extended_atof(const char *s)
{
/*skip white space*/
while (isspace(*s))
++s;
int sign = parse_sign(&s) ? 1 : -1; /*The sign of the number*/
double value = 0.0;
while (isdigit(*s))
value = value * 10.0 + (*s++ - '0');
if (*s == '.') {
++s;
}
double power = 1.0;
while (isdigit(*s)) {
value = value * 10.0 + (*s++ - '0');
power *= 10.0;
}
if (tolower(*s) == 'e') {
++s;
} else {
return sign * value/power;
}
bool powersign = parse_sign(&s); /*The sign following the E*/
int power2 = 0.0; /*The number following the E*/
while (isdigit(*s))
power2 = power2 * 10.0 + (*s++ - '0');
if (powersign) {
while (power2 != 0) {
power /= 10;
--power2;
}
} else {
while (power2 != 0) {
power *= 10;
--power2;
}
}
return sign * value/power;
}
It's slightly shorter, and it still passes all the tests.
Let's see if we can read digit strings in a function, and replace the three places we do that. We'll make it update a count of how many digits wore parsed, so we don't lose leading zeros in the fractional part:
double extended_atof(const char *s)
{
/*skip white space*/
while (isspace(*s))
++s;
int sign = parse_sign(&s) ? 1 : -1; /*The sign of the number*/
double value = parse_digits(&s, NULL);
if (*s == '.') {
++s;
int d; /* digits in fraction */
double fraction = parse_digits(&s, &d);
while (d--)
fraction /= 10.0;
value += fraction;
}
value *= sign;
if (tolower(*s) == 'e') {
++s;
} else {
return value;
}
bool powersign = parse_sign(&s); /*The sign following the E*/
int power2 = parse_digits(&s, NULL); /*The number following the E*/
double power = 1.0;
if (powersign) {
while (power2 != 0) {
power /= 10;
--power2;
}
} else {
while (power2 != 0) {
power *= 10;
--power2;
}
}
return value/power;
}
Tests still pass; what's next?
if (tolower(*s) == 'e') {
++s;
} else {
return value;
}
This can be reversed, and if we're returning, it doesn't matter what we do to s:
if (tolower(*s++) != 'e')
return value;
Here's some near-duplicate blocks:
double power = 1.0;
if (powersign) {
while (power2 != 0) {
power /= 10;
--power2;
}
} else {
while (power2 != 0) {
power *= 10;
--power2;
}
}
Dividing by 10 is the same as multiplying by 0.1, so we can move the test into the loop:
double power = 1.0;
while (power2 != 0) {
power *= powersign ? 0.1 : 10;
--power2;
}
We could go further, and capture powersign ? 0.1 : 10 into a variable. We can also eliminate the power variable from here, and multiply value directly:
const double exponentsign = parse_sign(&s) ? 10. : .1;
int exponent = parse_digits(&s, NULL);
while (exponent--)
value *= exponentsign;
Final version
Here's what I finished up with:
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
/* return true for positive, false for negative,
and advance `*s` to next position */
static bool parse_sign(const char **const s)
{
switch (**s) {
case '-': ++*s; return false;
case '+': ++*s; return true;
default: return true;
}
}
/* return decimal value of digits,
advancing `*s` to the next character,
and storing the number of digits read into *count */
static double parse_digits(const char **const s, int *const count)
{
double value = 0.0;
int c = 0;
while (isdigit(**s)) {
value = value * 10.0 + (*(*s)++ - '0');
++c;
}
if (count)
*count = c;
return value;
}
double extended_atof(const char *s)
{
/*skip white space*/
while (isspace(*s))
++s;
const bool valuesign = parse_sign(&s); /* sign of the number */
double value = parse_digits(&s, NULL);
if (*s == '.') {
int d; /* number of digits in fraction */
++s;
double fraction = parse_digits(&s, &d);
while (d--)
fraction /= 10.0;
value += fraction;
}
if (!valuesign)
value = -value;
if (tolower(*s++) != 'e')
return value;
/* else, we have an exponent; parse its sign and value */
const double exponentsign = parse_sign(&s) ? 10. : .1;
int exponent = parse_digits(&s, NULL);
while (exponent--)
value *= exponentsign;
return value;
}
/* Test program */
#include <stdio.h>
int main(void)
{
static const char *const strings[] = {
/* these should parse fully */
"12",
"12.0",
"08", /* not octal! */
"+12.34",
".34",
"\t \n2.",
"1e0",
"1e+0",
"1e-0",
"1.e4",
".1e-4",
"-5e006",
"-5e+16",
"-.05",
"-.0",
"-1e6",
/* these should parse only the initial part */
"5c5",
"10ee5",
"0x06", /* not hex! */
"--1" ,
"-+1" ,
"1e--4" ,
"-1e.4",
"1e 4",
"1e-g",
"", "foobar", /* both 0 */
" e5", /* also 0 */
"-1e6",
/* overflow/underflow */
"1e500000",
"1e-500000",
"-1e500000",
"-1e-500000",
};
static const int max = sizeof strings / sizeof strings[0];
for (int i = 0; i < max; ++i)
printf("%20s = > %.9g\n", strings[i], extended_atof(strings[i]));
}
There's still an opportunity for a small improvement: an extremely long fractional part could overflow double (this problem existed in your original). Instead of returning a large value from parse_int(), you could consider always returning a fractional value in the range [0...1), and use the number of digits to scale up the integer parts. Then we'd just end up with lost precision at the lower end. That would look like:
static double parse_digits(const char **const s, int *const count)
{
double value = 0.0;
double increment = 0.1;
int c = 0;
while (isdigit(**s)) {
value += increment * (*(*s)++ - '0');
increment /= 10;
++c;
}
if (count)
*count = c;
return value;
}
The corresponding uses would be:
double extended_atof(const char *s)
{
/*skip white space*/
while (isspace(*s))
++s;
int d; /* number of digits */
const bool valuesign = parse_sign(&s); /* sign of the number */
double value = parse_digits(&s, &d);
while (d--)
value *= 10;
if (*s == '.') {
++s;
double fraction = parse_digits(&s, NULL);
value += fraction;
}
if (!valuesign)
value = -value;
if (tolower(*s++) != 'e')
return value;
/* else, we have an exponent; parse its sign and value */
const double exponentsign = parse_sign(&s) ? 10. : .1;
double exponent_f = parse_digits(&s, &d);
while (d--)
exponent_f *= 10;
unsigned long exponent = exponent_f;
while (exponent-->0)
value *= exponentsign;
return value;
}
I think that the worst case of duplication that you need to remove from your code is writing another set of lines for reading the floating number after e (/E).
Even I am just a beginner and doing K&R right now. Here's what I thought when doing the exercise:
For extending the program to handle scientific notations the first thing that I require is to read another floating point number after the character e/E. The code for doing this is already present in the function. Which makes it obvious that we are to reuse that code somehow. I thought that no extra lines of code should should be written for implementing this functionality.
I found that using recursion along with math.h library shortened and simplified the code (particularly the part used for reading the number following e/E) quite considerably.
Here's the code that I wrote:
#include<stdio.h>
#include<ctype.h>
#include<math.h>
#include<string.h>
double atof(char *);
int main(void)
{
char num[20];
scanf("%19s", num);
double number=atof(num);
printf("\n%lf", number);
return 0;
}
double atof(char *num)
{
double val=0.0;
int place=1;
double expo=1.0;
int i=0;
int sign=1;
for(; isspace(num[i]); i++); //skip spaces
sign=(num[i]=='-')?-1:1; //determine sign
if(num[i]=='-'||num[i]=='+')
++i;
while(isdigit(num[i])){ //digits before decimal
val=(val*10)+(num[i]-'0');
++i;
}
if(num[i]=='.') //skip decimal point if present
++i;
while(isdigit(num[i])){ //digits after decimal
val=val*10+(num[i]-'0');
place*=10;
i++;
}
if(num[i]=='e' || num[i]=='E'){ //the extended part for scientific notations
++i;
expo=pow(10,atof(num+i));
}
return (sign*val*expo)/(place);
}
I agree with leppie's reply; to put that in terms of code:
string s = "123,456.789";
float f = float.Parse(s, CultureInfo.InvariantCulture);
Depends where the input is coming from.
If your input comes from the user, you should use the CultureInfo the user/page is using (Thread.CurrentThread.CurrentUICulture).
You can get and indication of the culture of the user, by looking at the HttpRequest.UserLanguages property. (Not correct 100%, but I've found it a very good first guess) With that information, you can set the Thread.CurrentThread.CurrentUICulture at the start of the page.
If your input comes from an internal source, you can use the InvariantCulture to parse the string.
The Parse method is somewhat easier to use, if your input is from a controlled source. That is, you have already validated the string. Parse throws a (slow) exception if its fails.
If the input is uncontrolled, (from the user, or other Internet source) the TryParse looks better to me.