SELECTED_REAL_KIND in C - c

Is there any equivalent of SELECTED_REAL_KIND (in Fortran) in C language ?

SELECTED_REAL_KIND is a standard Fortran mechanism for choosing at build time a real data type that meets or exceeds specified parameters for numeric representation. In particular, it is used to select a data type by precision and / or exponent range and / or radix.
Standard C does not have a built-in parameterized facility such as that for designating data types. It does have standard macros whose values describe the properties of the implementations of the standard floating-point types, float, double, and long double. Their joint radix, their precisions in both decimal digits and implementation-radix digits, and their minimum and maximum exponent values (also in both decimal and implementation-radix forms) are all available via these macros. These are defined in the standard header float.h. (The link is to POSIX, which is formally aligned with the C standard here.)
It is possible to use the C preprocessor conditionals and these macros to define macros or typedefs for types that meet your specific requirements, which you can then use throughout your code. This is not as tidy as Fortran's approach, but it gets the job done.

Related

Difference between INT_MAX and __INT_MAX__ in C

What is the difference between the 2? __INT_MAX__ is defined without adding a library as far as I know and INT_MAX is defined in limits.h but when I include the library INT_MAX gets expanded to __INT_MAX__ either way (or so does VSCode say). Why would I ever use the limits.h one when it gets expanded to the other one?
You should always use INT_MAX, as that is the macro constant that is defined by the ISO C standard.
The macro constant __INT_MAX__ is not specified by ISO C, so it should not be used, if you want your code to be portable. That macro is simply an implementation detail of the compiler that you are using. Other compilers will probably not define that macro, and will implement INT_MAX in some other way.
__INT_MAX__ is an implementation defined macro, which means not all systems may have it. In particular, GCC defines this macro but MSVC does not.
On the other hand, INT_MAX is defined by the C standard and is guaranteed to be present in limits.h for any conforming compiler.
So for portability, use INT_MAX.
Why would I ever use the limits.h one when it gets expanded to the other one?
limits.h is standard and portable.
Every implementation of the C language is free to create the value of macros such as INT_MAX as it sees fit. The __INT_MAX__ value you are seeing is an artifact of your particular compiler, and maybe even the particular version of the compiler you're using.
To add to the other answers, when you're writing code that will be run on several platforms, it really pays to stick to the standards. If you don't, when a new platform comes along, you have a lot of work to do adapting it, and the best way to do that is usually to change it conform to the standard. This work is very dull and uninteresting, and well worth avoiding by doing things right to start with.
I work on a mathematical modeller that was originally written in the 1980s on VAX/VMS, and in its early days supported several 68000 platforms, including Apollo/Domain. Nowadays, it runs on 64-bit Windows, Linux, macOS, Android and iOS, none of which existed when it was created.
__INT_MAX__ is a predefined macro in the C preprocessor that specifies the maximum value of an int type on a particular platform. This value is implementation-defined and may vary across different platforms.
INT_MAX is a constant defined in the limits.h header file that specifies the maximum value of an int type. It is defined as follows:
define INT_MAX __INT_MAX__
The limits.h header file is part of the C standard library and provides various constants that specify the limits of various types, such as the minimum and maximum values of the int, long, and long long types.
The reason why INT_MAX is defined as __INT_MAX__ is because __INT_MAX__ is a predefined macro that specifies the maximum value of an int type on a particular platform, and INT_MAX is simply an alias for this value.
You can use either __INT_MAX__ or INT_MAX to get the maximum value of an int type, but it is generally recommended to use INT_MAX since it is defined in a standard library header file and is therefore more portable.
INT_MAX is a macro that specifies that an integer variable cannot store any value beyond this limit.
INT_MIN specifies that an integer variable cannot store any value below this limit.
Values of INT_MAX and INT_MIN may vary
from compiler to compiler. Following are
typical values in a compiler where integers
are stored using 32 bits.
Value of INT_MAX is +2147483647.
Value of INT_MIN is -2147483648.
In the C programming language, INT_MAX is a macro that expands to the maximum value that can be stored in a variable of type int. This value is implementation-defined, meaning that it may vary depending on the specific C implementation being used. On most systems, int is a 32-bit data type and INT_MAX is defined as 2147483647, which is the maximum value that can be stored in a 32-bit, two's complement integer.
On the other hand, __INT_MAX__ is a predefined macro that represents the maximum value that can be stored in a variable of type int on the system where the C program is being compiled. Like INT_MAX, the value of __INT_MAX__ is implementation-defined and may vary depending on the specific C implementation being used. However, __INT_MAX__ is set by the compiler during compilation, whereas INT_MAX is typically defined in a header file (e.g., limits.h) and included in the program at runtime.
In general, it is recommended to use INT_MAX rather than __INT_MAX__ in C programs, as INT_MAX is portable and will work on any system, whereas __INT_MAX__ is specific to the system where the program is being compiled.
INT_MAX (macro) : It specifies that any integer variable cannot store values beyond the mentioned limit.
whereas
INT_MIN specifies that any integer variable cannot store some value that is below the mentioned limit.

Example of an extended integer type?

As of C99, C supports implementation-defined extended integer types (6.2.5 p7). Does any implementation actually implement an extended integer type?
I'm aware of gcc's __int128, which is currently treated as a language extension and is not formally listed as an extended integer type in gcc's documentation of implementation-defined behavior (J.3.5). I couldn't find anything mentioned in the documentation for clang or MSVC. Solaris states that there are no extended integer types.
There is some related discussion at What are “extended integer types”?, but the only other candidate mentioned is __int64 in an older version of MSVC, and the comments seem to agree that it's not a formal extended integer type due to that version of MSVC being C90.
Example of an extended integer type?
Does any implementation actually implement an extended integer type?
Various processors have a 24-bit width for instructions and constant memory.
Compilers supporting such Microchip processors offer
(u)int24_t.
int24_t types added to C99 The int24_t and uint24_t types (along with the existing __int24 and __uint24 types) are now available when using the C99 library and when CCI is not active.
Even though some compilers do offer 128-bit integer types, if that type was an extended integer type, the C library would require (u)intmax_t to be at least that width. C11dr 7.20.1.5
C also requires "preprocessor arithmetic done in intmax_t/uintmax_t".
I suspect compilers offering intN (N > 64) do so as a language extension.
I know of no compiler where (u)int128_t exist (as an extended integer type).

Is `x!=x` a portable way to test for NaN?

In C you can test to see if a double is NaN using isnan(x). However many places online, including for example this SO answer say that you can simply use x!=x instead.
Is x!=x in any C specification as a method that is guaranteed to test if x is NaN? I can't find it myself and I would like my code to work with different compilers.
NaN as the only value x with the property x!=x is an IEEE 754 guarantee. Whether it is a faithful test to recognize NaN in C boils down to how closely the representation of variables and the operations are mapped to IEEE 754 formats and operations in the compiler(s) you intend to use.
You should in particular worry about “excess precision” and the way compilers deal with it. Excess precision is what happens when the FPU only conveniently supports computations in a wider format than the compiler would like to use for float and double types. In this case computations can be made at the wider precision, and rounded to the type's precision when the compiler feels like it in an unpredictable way.
The C99 standard defined a way to handle this excess precision that preserved the property that only NaN was different from itself, but for a long time after 1999 (and even nowadays when the compiler's authors do not care), in presence of excess precision, x != x could possibly be true for any variable x that contains the finite result of a computation, if the compiler chooses to round the excess-precision result of the computation in-between the evaluation of the first x and the second x.
This report describes the dark times of compilers that made no effort to implement C99 (either because it wasn't 1999 yet or because they didn't care enough).
This 2008 post describes how GCC started to implement the C99 standard for excess precision in 2008. Before that, GCC could provide one with all the surprises described in the aforementioned report.
Of course, if the target platform does not implement IEEE 754 at all, a NaN value may not even exist, or exist and have different properties than specified by IEEE 754. The common cases are a compiler that implements IEEE 754 quite faithfully with FLT_EVAL_METHOD set to 0, 1 or 2 (all of which guarantee that x != x iff x is NaN), or a compiler with a non-standard implementation of excess precision, where x != x is not a reliable test for NaN.
Please refer to the normative section Annex F: IEC 60559 floating-point arithmetic of the C standard:
F.1 Introduction
An implementation that defines __STDC_IEC_559__ shall conform to the specifications in this annex.
Implementations that do not define __STDC_IEC_559__ are not required to conform to these specifications.
F.9.3 Relational operators
The expression x ≠ x is true if x is a NaN.
The expression x = x is false if X is a Nan.
F.3 Operators and functions
The isnan macro in <math.h> provides the isnan function recommended in the Appendix to IEC 60559.

How do I get DOUBLE_MAX?

AFAIK, C supports just a few data types:
int, float, double, char, void enum.
I need to store a number that could reach into the high 10 digits. Since I'm getting a low 10 digit # from
INT_MAX
, I suppose I need a double.
<limits.h> doesn't have a DOUBLE_MAX. I found a DBL_MAX on the internet that said this is LEGACY and also appears to be C++. Is double what I need? Why is there no DOUBLE_MAX?
DBL_MAX is defined in <float.h>. Its availability in <limits.h> on unix is what is marked as "(LEGACY)".
(linking to the unix standard even though you have no unix tag since that's probably where you found the "LEGACY" notation, but much of what is shown there for float.h is also in the C standard back to C89)
You get the integer limits in <limits.h> or <climits>. Floating point characteristics are defined in <float.h> for C. In C++, the preferred version is usually std::numeric_limits<double>::max() (for which you #include <limits>).
As to your original question, if you want a larger integer type than long, you should probably consider long long. This isn't officially included in C++98 or C++03, but is part of C99 and C++11, so all reasonably current compilers support it.
Its in the standard float.h include file. You want DBL_MAX
Using double to store large integers is dubious; the largest integer that can be stored reliably in double is much smaller than DBL_MAX. You should use long long, and if that's not enough, you need your own arbitrary-precision code or an existing library.
You are looking for the float.h header.
INT_MAX is just a definition in limits.h. You don't make it clear whether you need to store an integer or floating point value. If integer, and using a 64-bit compiler, use a LONG (LLONG for 32-bit).

Is it legal to use memset(…, 0, …) on an array of doubles?

Is it legal to zero the memory of an array of doubles (using memset(…, 0, …)) or struct containing doubles?
The question implies two different things:
From the point of view of C standard: Is this undefined behavior of not? (On any particular platform, I presume, this cannot be undefined behavior, as it just depends on the in-memory representation of floating-point numbers—that’s all.)
From practical point of view: Is it OK on Intel platform? (Regardless of what the standard is saying.)
The C99 standard Annex F says:
This annex specifies C language support for the IEC 60559 floating-point standard. The
IEC 60559 floating-point standard is specifically Binary floating-point arithmetic for
microprocessor systems, second edition (IEC 60559:1989), previously designated
IEC 559:1989 and as IEEE Standard for Binary Floating-Point Arithmetic
(ANSI/IEEE 754−1985). IEEE Standard for Radix-Independent Floating-Point
Arithmetic (ANSI/IEEE 854−1987) generalizes the binary standard to remove
dependencies on radix and word length. IEC 60559 generally refers to the floating-point
standard, as in IEC 60559 operation, IEC 60559 format, etc. An implementation that
defines __STDC_IEC_559__ shall conform to the specifications in this annex. Where
a binding between the C language and IEC 60559 is indicated, the IEC 60559-specified
behavior is adopted by reference, unless stated otherwise.
And, immediately after:
The C floating types match the IEC 60559 formats as follows:
The float type matches the IEC 60559 single format.
The double type matches the IEC 60559 double format.
Thus, since IEC 60559 is basically IEEE 754-1985, and since this specifies that 8 zero bytes mean 0.0 (as #David Heffernan said), it means that if you find __STDC_IEC_559__ defined, you can safely do a 0.0 initialization with memset.
If you are talking about IEEE754 then the standard defines +0.0 to double precision as 8 zero bytes. If you know that you are backed by IEEE754 floating point then this is well-defined.
As for Intel, I can't think of a compiler that doesn't use IEEE754 on Intel x86/x64.
David Heffernan has given a good answer for part (2) of your question. For part (1):
The C99 standard makes no guarantees about the representation of floating-point values in the general case. §6.2.6.1 says:
The representations of all types are unspecified except as stated in this subclause.
...and that subclause makes no further mention of floating point.
You said:
(on a fixed platform, how can this UB ... it just depends of floating representation that's all ...)
Indeed - there a difference between "undefined behaviour", "unspecified behaviour" and "implementation-defined behaviour":
"undefined behaviour" means that anything could happen (including a runtime crash);
"unspecified behaviour" means that the compiler is free to implement something sensible in any way it likes, but there is no requirement for the implementation choice to be documented;
"implementation-defined behaviour" means that the compiler is free to implement something sensible in any way it likes, and is supposed to document that choice (for example, see here for the implementation choices documented by the most recent release of GCC);
and so, as floating point representation is unspecified behaviour, it can vary in an undocumented manner from platform to platform (where "platform" here means "the combination of hardware and compiler" rather than just "hardware").
(I'm not sure how useful the guarantee that a double is represented such that all-bits-zero is +0.0 if __STDC_IEC_559__ is defined, as described in Matteo Italia's answer, actually is in practice. For example, GCC never defines this, even though is uses IEEE 754 / IEC 60559 on many hardware platforms.)
Even though it is unlikely that you encounter a machine where this has problems, you may also avoid this relatively easily if you are really talking of arrays as you indicate in the question title, and if these arrays are of known length at compile time (that is not VLA), then just initializing them is probably even more convenient:
double A[133] = { 0 };
should always work. If you'd have to zero such an array again, later, and your compiler is compliant to modern C (C99) you can do this with a compound literal
memcpy(A, (double const[133]){ 0 }, 133*sizeof(double));
on any modern compiler this should be as efficient as memset, but has the advantage of not relying on a particular encoding of double.
As Matteo Italia says, that’s legal according to the standard, but I wouldn’t use it. Something like
double *p = V, *last = V + N; // N is count
while (p != last) *(p++) = 0;
is at least twice faster.
It’s “legal” to use memset. The issue is whether it produces a bit pattern where array[x] == 0.0 is true. While the basic C standard doesn’t require that to be true, I’d be interested in hearing examples where it isn’t!
It appears that setting to zero via memset is equivalent to assigning 0.0 on IBM-AIX, HP-UX (PARISC), HP-UX (IA-64), Linux (IA-64, I think).
Here is a trivial test code:
double dFloat1 = 0.0;
double dFloat2 = 111111.1111111;
memset(&dFloat2, 0, sizeof(dFloat2));
if (dFloat1 == dFloat2) {
fprintf(stdout, "memset appears to be equivalent to = 0.0\n");
} else {
fprintf(stdout, "memset is NOT equivalent to = 0.0\n");
}
Well, I think the zeroing is "legal" (after all, it's zeroing a regular buffer), but I have no idea if the standard lets you assume anything about the resulting logical value. My guess would be that the C standard leaves it as undefined.

Resources