(C++) Is it possible to initialize a float variable with a hexademical float point value?
something like so:
\'0x011.1\' // wrong!
The Technical Specification P0245 Hexadecimal floating literals for C++ has been voted into C++17 at the ISO C++ Standards Committee in Jacksonville, Florida on February 2016.
The language C99 also has this feature, and the C++ feature is compatible.
However, as pointed by the Lưu Vĩnh Phúc's comment, the syntax 0x011.1
is not part of the standard. The binary exponent is mandatory for hexadecimal floating-point literals. One reason is to avoid ambiguity of the trailing F
within 0x011.1F
. Is it the hex digit F
of the fractional part or the floating-suffix meaning float
?
Therefore append p
followed by a positive or negative decimal number, for example: 0x011.1p0
.
See the more readable page floating literal page on cppreference.com.
0x | 0X hex-digit-sequence
0x | 0X hex-digit-sequence .
0x | 0X hex-digit-sequence(optional) . hex-digit-sequence
Hexadecimal digit-sequence representing a whole number without a radix separator. The exponent is never optional for hexadecimal floating-point literals:
0x1ffp10
,0X0p-1
,0x1.p0
,0xf.p-1
,0x0.123p-1
,0xa.bp10l
The exponent syntax for hexadecimal floating-point literal has the form
p | P exponent-sign(optional) digit-sequence
exponent-sign, if present, is either + or -
suffix, if present, is one of
f
,F
,l
, orL
. The suffix determines the type of the floating-point literal:
- (no suffix) defines double
f F
defines floatl L
defines long double
See also the current working draft C++17, chapter § 2.13.4 Floating literals on GitHub: https://github.com/cplusplus/draft/raw/master/papers/n4604.pdf
floating-literal:
decimal-floating-literal
hexadecimal-floating-literal
decimal-floating-literal:
fractional-constant exponent-partopt floating-suffixopt
digit-sequence exponent-part floating-suffixopt
hexadecimal-floating-literal:
hexadecimal-prefix hexadecimal-fractional-constant binary-exponent-part floating-suffixopt
hexadecimal-prefix hexadecimal-digit-sequence binary-exponent-part floating-suffixopt
fractional-constant:
digit-sequenceopt . digit-sequence
digit-sequence .
hexadecimal-fractional-constant:
hexadecimal-digit-sequenceopt . hexadecimal-digit-sequence
hexadecimal-digit-sequence .
exponent-part:
e
signopt digit-sequence
E
signopt digit-sequence
binary-exponent-part:
p
signopt digit-sequence
P
signopt digit-sequence
sign: one of
+
-
digit-sequence:
digit
digit-sequence ’opt digit
floating-suffix: one of
f
l
F
L
1 A floating literal consists of an optional prefix specifying a base, an integer part, a radix point, a fraction part, an
e
,E
,p
orP
, an optionally signed integer exponent, and an optional type suffix. The integer and fraction parts both consist of a sequence of decimal (base ten) digits if there is no prefix, or hexadecimal (base sixteen) digits if the prefix is0x
or0X
. The literal is a decimal floating literal in the former case and a hexadecimal floating literal in the latter case. Optional separating single quotes in a digit-sequence or hexadecimal- digit-sequence are ignored when determining its value. [ Example: The literals1.602’176’565e-19
and1.602176565e-19
have the same value. — end example ] Either the integer part or the fraction part (not both) can be omitted. Either the radix point or the letter e or E and the exponent (not both) can be omitted from a decimal floating literal. The radix point (but not the exponent) can be omitted from a hexadecimal floating literal. The integer part, the optional radix point, and the optional fraction part, form the significand of the floating literal. In a decimal floating literal, the exponent, if present, indicates the power of 10 by which the significand is to be scaled. In a hexadecimal floating literal, the exponent indicates the power of 2 by which the significand is to be scaled. [ Example: The literals49.625
and0xC.68p+2
have the same value. — end example ] If the scaled value is in the range of representable values for its type, the result is the scaled value if representable, else the larger or smaller representable value nearest the scaled value, chosen in an implementation-defined manner. The type of a floating literal isdouble
unless explicitly specified by a suffix. The suffixesf
andF
specifyfloat
, the suffixesl
andL
specifylong double
. If the scaled value is not in the range of representable values for its type, the program is ill-formed.
As unwind has advised, you can use strtof(). The following snippet decodes Hexadecimal floating literals (without C++17):
#include <iostream>
#include <cstdlib>
#include <cstdio>
int main(int argc, char *argv[])
{
if (argc != 2)
{
std::cout <<"Usage: "<< argv[0] <<" 0xA.Bp-1 => Decode hexfloat" "\n";
return 1;
}
long double l;
double d;
float f;
std::cout <<"Decode floating point hexadecimal = "<< argv[1];
//std::istringstream(argv[1]) >> std::hexfloat >> d;
l = std::strtold(argv[1],NULL); if(errno == ERANGE) std::cout << "\n" "std::strtold() range error";
d = std::strtod (argv[1],NULL); if(errno == ERANGE) std::cout << "\n" "std::strtod() range error";
f = std::strtof (argv[1],NULL); if(errno == ERANGE) std::cout << "\n" "std::strtod() range error";
std::cout <<"\n" "long double = "<< std::defaultfloat << l <<'\t'<< std::hexfloat << l
<<"\n" "double = "<< std::defaultfloat << d <<'\t'<< std::hexfloat << d
<<"\n" "float = "<< std::defaultfloat << f <<'\t'<< std::hexfloat << f <<'\n';
}
No, C++ doesn't support that for literals, it's not part of the standard.
A non-portable solution is to use a compiler that adds this as an extension (GCC does this).
A portable workaround is to parse them from string literals at runtime using e.g. strtof() or strtod()
for double
.
As pointed out in a comment, you can also opt to store the constants in a C file. Doing so requires that you have access to a C99 compiler though, since hex float literals is a C99-level feature. Since environments with a new C++ compiler but without a C99 compiler (read: Visual Studio) are quite common, that might not be a workable solution.
Update: C++17 supports hexadecimal floating point literals.