How to print long double number in xinu? - c

Function sqrtl doesn't work here, also the printf of long double prints f for all given numbers:
#include <conf.h>
#include <kernel.h>
#include <math.h>
#include <float.h>
long double sqrtn;
unsigned long int n;
void xmain() {
unsigned long int n;
printf("Enter unsigned long integer:\n");
scanf("%lu", &n);
sqrtn = sqrtl(long double)n);
printf("\nsqrtn=%Lf\n", sqrtn);
} /* main */

I downloaded the Xinu source code for x86 from https://xinu.cs.purdue.edu/files/Xinu-code-Galileo.tar.gz .
Looking at the implementation for printf (lib/printf.c lib/doprnt.c), as far as I can tell it simply doesn't support length modifiers. That means that, for example, this:
long int n = 42;
printf("%ld\n", n);
wouldn't work. I suggest trying that on your system.
This is not a conforming C implementation (and it's probably not intended to be).
It does appear to support most of the standard conversion specifiers ("%d", "%u", "%x", "%f", etc.).
If you want to print a long double value, I think the best you can do is either convert it to double and use "%f" (which could lose range and/or precision) or write your own code to convert a long double value to a string. (Or run you code on a different system).
Disclaimer: I haven't tried this, I've only examined the source code, and only for the x86 version of the system.

I was worried about long double won't print.
i wrote a small test and found out that my MAC wanted to have %Lf or %Le.
it seems that capital L must be used.

Related

The problem about printf function to "output float with %d" in C

I am a newbie to the C language. When I was learning floating point numbers today, I found the following problems.
float TEST= 3.0f;
printf("%x\n",TEST);
printf("%d\n",TEST);
first output:
9c9e82a0
-1667333472
second output:
61ea32a0
1642738336
As shown above, each execution will output different results. I have checked a lot of IEEE 754 format and still don't understand the reasons. I would like to ask if anyone can explain or provide keywords for me to study, thank you.
-----------------------------------Edit-----------------------------------
Thank you for your replies. I know how to print IEEE 754 bit pattern. However, as Nate Eldredge, chux-Reinstate Monica said, using %x and %d in printf is undefined behavior. If there is no floating point register in our device, how does it work ? Is this described in the C99 specification?
Most of the time, when you call a function with the "wrong kind" (wrong type) of argument, an automatic conversion happens. For example, if you write
#include <stdio.h>
#include <math.h>
printf("%f\n", sqrt(144));
this works just fine. The compiler knows (from the function prototype in <math.h>) that the sqrt function expects an argument of type double. You passed it the int value 144, so the compiler automatically converted that int to double before passing it to sqrt.
But this is not true for the printf function. printf accepts arguments of many different types, and as long as each argument is right for the particular % format specifier it goes with in the format string, it's fine. So if you write
double f = 3.14;
printf("%f\n", f);
it works. But if you write
printf("%d\n", f); /* WRONG */
it doesn't work. %d expects an int, but you passed a double. In this case (because printf is special), there's no good way for the compiler to insert an automatic conversion. So, instead, it just fails to work.
And when it "fails", it really fails. You don't even necessarily get anything "reasonable", like an integer representing the bit pattern of the IEEE-754 floating-point number you thought you passed. If you want to inspect the bit pattern of a float or double, you'll have to do that another way.
If what you really wanted to do was to see the bits and bytes making up a float, here's a completely different way:
float test = 3.14;
unsigned char *p = (unsigned char *)&test;
int i;
printf("bytes in %f:", test);
for(i = 0; i < sizeof(test); i++) printf(" %02x", p[i]);
printf("\n");
There are some issues here with byte ordering ("endianness"), but this should get you started.
To print hex (ie how it is represented in the memory) representation of the float:
float TEST= 3.0f;
int y=0;
memcpy(&y, &TEST, sizeof(y));
printf("%x\n",y);
printf("%d\n",y);
or
union
{
float TEST;
int y;
}uf = {.y = 0};
uf.TEST = 3.0f;
printf("\n%x\n",(unsigned)uf.y);
printf("%d\n",uf.y);
Both examples assuming sizeof(float) <= sizeof(int) (if they are not equal I need to zero the integer)
And the result (same for both):
40400000
1077936128
As you can see it is completely different from your one.
https://godbolt.org/z/Kr61x6Kv3

function return changed as directly written in printf statement

#include <stdio.h>
#include <math.h>
int main() {
printf("%d\n", pow(3546, 0));
return 0;
}
The above code prints value 0
While the below code prints value 1
#include <stdio.h>
#include <math.h>
int main() {
int a = pow(3546, 0);
printf("%d\n", a);
return 0;
}
Why is it so? Even though they are equivalent.
There's no equivalence. The latter function explicitly converts the number to int before printing, while the former results in UB by trying to print a floating point number using wrong format specifier -- you're lucky to get 0, you might have gotten an arbitrary number.
Please, turn on all warnings on your compiler, it should complain about using wrong format for the wrong type of data.
pow returns a result of type double, and %d is not a correct conversion specifier to use to format it. The resulting behavior is not defined by the C standard.
To print a double, you can use %g or %f, among other options:
printf("%g\n", pow(3456, 0));
printf("%f\n", pow(3456, 0));
In int a = pow(3546,0);, the double value is automatically convert to an int for the initialization of the int a, and then printing that int with %d is correct.
As mentioned in this answer, printf uses the format specifiers to know what to pop off the stack (%d is sizeof(int), which is 4 bytes in my system).
(Edit: As pointed out by rici in the comments, it's not guaranteed to be the stack (on x86 it's in the CPU registers most of the time). The standard never talks about implementations, which is what this problem is all about.)
A small fun fact: in my Windows 10 box it was 0 and 1. In my Xubuntu VBox it was 1 and -2132712864. Therefore, printf is poping only 4 bytes, and the endianess of your machine is screwing the result. From pow(3) manual:
#include <math.h>
double pow(double x, double y);
float powf(float x, float y);
long double powl(long double x, long double y);
So, in order to get the correct result in both cases, make use of the correct printf format specifier:
double a = pow(3546, 0);
And:
printf("%lf\n", pow(3546, 0));
If you want to know more about variadic functions (the ones like printf, which take a variable amount of parameters), start by reading the API manual page.
#include <stdarg.h>
void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);

ATmega64a float to IEEE-754 unexpected result

I am trying to convert a float to an IEEE-754 Hex representation. The following code works on my Mac.
#include <stdio.h>
#include <stdlib.h>
union Data {
int i;
float f;
};
int main() {
float var = 502.7;
union Data value;
value.f = var;
printf("%08X\n", value.i);
return 0;
}
This is giving me the expected result of 43FB599A.
When I run this code on an ATmega64a I am getting 0000599A not 04A2599A as originally posted which was a mistake.
The first two bytes are not expected but the final two bytes seem correct?
Any ideas?
As mentioned in the accepted answer the I was assuming that int was 4 bytes. I was writing the code on my mac and sending it to someone that was downloading it to an 8-bit ATmega64a. On the ATmega64a int is 2 bytes, not 4. I changed int to unsigned long which is 4 bytes on the ATmega64a.
In addition, I had to add a length sub-specifier of l to the format given to printf. This is because when given a specifier of x, printf uses a type of unsigned int to interpret the corresponding argument. Adding the length sub-specifier of l tells printf to use the type of unsigned long to interpret the corresponding argument.
Using only the length sub-specifier of l and not changing the variable i to unsigned long was causing printf to grab some extra bytes and output 04A2599A as originally posted. I, of course, needed to change the type of i to unsigned long as well as use the length sub-specifier of l.
http://www.cplusplus.com/reference/cstdio/printf/
This processor is an 8 bit one which mean size of int is most likely 2 byte not 4 as your code assume.
Try to use uint32_t rather then int if you can.

Negative output for long double

Why is the following code giving answer as -2.000000 for every input?
#include <stdio.h>
#include <math.h>
int main()
{
long long int s1,s2;
long double l,y,m=sqrt(2);
scanf("%Lf %lld %lld",&l,&s1,&s2);
y=l*m;
printf("%Lf\n",y);
}
You might have made some kind of strange modification to your floating-point environment in the compiler settings. Maybe the bit that represents the exponent now represents the number itself.

Why we can't use operator % for float and double type operands?

I am new to C/C++, so I have a couple of questions about a basic type:
I have read somewhere that the operator % can't be applied to float or double type operands.
Then how can I check the divisibility of float or double type variables? I have shown my program with error below:
#include <stdio.h>
int main()
{
double n,k,t,i;
int j=0;
scanf("%f %f",&n,&k);
i=0;
while(i<n)
{
scanf("%f",&t);
if(t%k==0) /* error:invalid operands to binary % */
j++;
i++;
}
printf("%d",j);
return 0;
}
If a positive integer has a range up to 10^9, which qualifier should I use or how to achieve such a large range?
then how can i check the divisibility of float or double type variables. ??`
Use fmod. % only work with integer operands. % does not work with floating point values because C already provides the fmod library function.
Use the function fmod and its family.
a. if you want to keep it in floating point, use the fmod function from <math.h> (std::fmod from <cmath> in C++).
b. the int range is implementation-dependent (although the standard defines a minimum range that, IIRC, should be of +-32767, although on typical machines it will be -2147483648 - 2147483647). If an integer number is in the range of int you don't have to do anything particular - an integer literal without suffixes is automatically taken for an int if it fits in its range. On the other hand, bigger integer literals may need to be stored in a long or long long to avoid overflow.
Here is an alternative to the fmod answers - which answer the question you originally asked (since you were using double type. If, as is clear from your comments, you actually want to use integer types only, you can rewrite your code as follows (with the unsigned long long int type to give you plenty of headroom):
#include <stdio.h>
int main()
{
unsigned long long int n, k, t, i, j=0;
printf("enter the number of attempts: ");
scanf("%llu", &n);
printf("\nEnter the factor: ");
scanf("%llu", &k);
i=0;
while(i<n)
{
printf("\nEnter the number to test: ");
scanf("%llu",&t);
if(t%k==0)
j++;
i++;
}
printf("The number of multiples found was %llu\n", j);
return 0;
}
Note I have attempted to make the I/O a little more descriptive - it is a good idea to prompt the user, rather than just have a blinking cursor waiting for him. Obviously I am guessing at the prompts a bit (may not even be the language you want to use...)
% can't be used on floats because the standard says so. Use fmod. Okay okay okay, the actual reason is that the concept of a "remainder" only makes sense for integer division. What fmod does is produce an integer quotient for two floating-point arguments:
float my_fmod(float a, float b)
{
int quot = (int) a/b;
return a - (quot * b);
}
If you need a specific range for an integer, don't use int with qualifiers since they are implementation-specific. Use a fixed-width type like uint32_t.

Resources