floating point - absolute value - inline assembly - edited new code - c

I wrote a function named absD that i want to return the absolute value of its argument..
I am using GCC inline assembly with cygwin..
I dont see why its not working. i m loading into memory. then into st(0)
where i am using fabs - absolute value. Do i have to allocate memory?
I am trying to learn assembly with C here so please be nice. Please give me good help.
Thank you
heres the code and then the error:
#include <stdio.h>
#include <stdlib.h>
#define PRECISION 3
double absD (double n)
{
asm(
"fldl %[nIn]\n"
"fabs\n"
"fstpl %[nOut]\n"
: [nOut] "=m" (n)
: [nIn] "m" (n)
);
return n;
}
int main (int argc, char **argv)
{
double n = 0.0;
printf("Absolute value\n");
if (argc > 1)
n = atof(argv[1]);
printf("abs(%.*f) = %.*f\n", PRECISION, n, PRECISION, absD(n));
return 0;
}
here is the output:
~ $ gc a3
gcc -Wall -g a3.c -o a3
~ $ ./a3
Absolute value
abs(0.000) = 0.000
~ $
Not outputing its absolute value...
Thank you..

It is completely working..!! You are just forgetting to put values to argv. You can run the program with something like this:
./a3 -1.3
and it should return 1.3
you were done before posting it here...

fld (%eax) means "load a float from the value at address %eax". Obviously, the contents of %eax are a double, and not a pointer to a float, which is why you segfault.
Since the input is already on the stack (thus it has an address), there's no need to jump through hoops moving things around.
double absD(double input) {
double output;
asm(
"fldl %[input]\n"
"fabs\n"
"fstpl %[output]\n"
: [output] "=m" (output)
: [input] "m" (input)
);
return output;
}
Also, your printf format is wrong: %f means float, but you're giving it a double; you want to use %g.

Related

atan2f gives different results with m32 flag

I'm porting some code from 32 bit to 64 bit, and ensuring the answers are the same. In doing so, I noticed that atan2f was giving different results between the two.
I created this min repro:
#include <stdio.h>
#include <math.h>
void testAtan2fIssue(float A, float B)
{
float atan2fResult = atan2f(A, B);
printf("atan2f: %.15f\n", atan2fResult);
float atan2Result = atan2(A, B);
printf("atan2: %.15f\n", atan2Result);
}
int main()
{
float A = 16.323556900024414;
float B = -5.843180656433105;
testAtan2fIssue(A, B);
}
When built with:
gcc compilerTest.c -m32 -o 32bit.out -lm
it gives:
atan2f: 1.914544820785522
atan2: 1.914544820785522
When built with:
gcc compilerTest.c -o 64bit.out -lm
it gives:
atan2f: 1.914544701576233
atan2: 1.914544820785522
Note that atan2 gives the same result in both cases, but atan2f does not.
Things I have tried:
Building the 32 bit version with -ffloat-store
Building the 32 bit version with -msse2 -mfpmath=sse
Building the 64 bit version with -mfpmath=387
None changed the results for me.
(All of these were based on the hypothesis that it has something to do with the way floating point operations happen on 32 bit vs 64 bit architectures.)
Question:
What are my options for getting them to give the same result? (Is there a compiler flag I could use?) And also, what is happening here?
I'm running on an i7 machine, if that is helpful.
This is easier to see in hex notation.
void testAtan2fIssue(float A, float B) {
double d = atan2(A, B);
printf(" atan2 : %.13a %.15f\n", d, d);
float f = atan2f(A, B);
printf(" atan2f: %.13a %.15f\n", f, f);
printf("(float) atan2 : %.13a %.15f\n", (float) d, (float) d);
float f2 = nextafterf(f, 0);
printf("problem value : %.13a %.15f\n", f2, f2);
}
// _ added for clarity
atan2 : 0x1.ea1f9_b9d85de4p+0 1.914544_797857041
atan2f: 0x1.ea1f9_c0000000p+0 1.914544_820785522
(float) atan2 : 0x1.ea1f9_c0000000p+0 1.914544_820785522
problem value : 0x1.ea1f9_a0000000p+0 1.914544_701576233
what is happening here?
The conversion from double to float can be expected to be optimal, yet arctangent functions may be a few ULP off on various platforms. The 1.914544701576233 is the next smaller float value and reflects the slightly inferior arctangent calculation.
What are my options for getting them to give the same result?
Few. Code could roll your own my_atan2() from an established code base. Yet even that may have subtle implementation differences. #stark
Instead, consider making code checking tolerant of the minute variations.

Weird C program behaviour

I have the following C program:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
int main() {
const int opt_count = 2;
int oc = 30;
int c = 900;
printf("%d %f\n", c, pow(oc, opt_count));
assert(c == (int)(pow(oc, opt_count)));
}
I'm running MinGW on Windows 8.1. Gcc version 4.9.3. I compile my program with:
gcc program.c -o program.exe
When I run it I get this output:
$ program
900 900.000000
Assertion failed: c == (int)(pow(oc, opt_count)), file program.c, line 16
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
What is going on? I expect the assertion to pass because 900 == 30^2.
Thanks!
Edit
I'm not using any fractions or decimals. I'm only using integers.
This happens when the implementation of pow is via
pow(x,y) = exp(log(x)*y)
Other library implementations first reduce the exponent by integer powers, thus avoiding this small floating point error.
More involved implementations contain steps like
pow(x,y) {
if(y<0) return 1/pow(x, -y);
n = (int)round(y);
y = y-n;
px = x; powxn = 1;
while(n>0) {
if(n%2==1) powxn *= px;
n /=2; px *= px;
}
return powxn * exp(log(x)*y);
}
with the usual divide-n-conquer resp. halving-n-squaring approach for the integer power powxn.
You have a nice answer (and solution) from #LutzL, another solution is comparing the difference with an epsilon, e.g.: 0.00001, in this way you can use the standard function pow included in math.h
#define EPSILON 0.0001
#define EQ(a, b) (fabs(a - b) < EPSILON)
assert(EQ((double)c, pow(oc, opt_count)));

C program to find roots error

I am writing a function in C with the below specifications:
float find_root(float a, float b, float c, float p, float q);
find_root takes the coefficients a,b,c of a quadratic equation and an interval (p, q). It will return the root of this equation in the given interval.
For example: find_root(1, -8, 15, 2, 4) should produce a root "close to" 3.0
I have written the below code, and I don't understand why it doesn't work:
#include<stdio.h>
#include<math.h>
main()
{
printf("Hello World");
}
float find_root(float a, float b, float c, float p, float q) {
float d,root1,root2;
d = b * b - 4 * a * c;
root1 = ( -b + sqrt(d)) / (2* a);
root2 = ( -b - sqrt(d)) / (2* a);
if (root1<=q || root1>=p)
{
return root1;
}
return root2;
}
Please let me know what the error is.
Your program doesn't work, because, you never called find_root() from your main().
find_root() is not suppossed to run all-by-itself. Your program statrs execution from main(). You need to call your sub-function from main() in order to make them execute.
Change your main to have a call to find_root(), something like below.
int main() //put proper signature
{
float anser = 0;
answer = find_root(1, -8, 15, 2, 4); //taken from the question
printf("The anser is %f\n", answer); //end with a \n, stdout is line buffered
return 0; //return some value, good practice
}
Then, compile the program like
gcc -o output yourfilename.c -lm
Apart from this, for the logical issue(s) in find_root() function, please follow the way suggested by Mr. #paxdiablo.
For that data, your two roots are 5 and 3. With p == 2 and q == 4:
if (root1<=q || root1>=p)
becomes:
if (5<=4 || 5>=2)
which is true, so you'll get 5.
The if condition you want is:
if ((p <= root1) && (root1 <= q))
as shown in the following program, that produces the correct 3:
#include<stdio.h>
#include<math.h>
float find_root (float a, float b, float c, float p, float q) {
float d,root1,root2;
d = b * b - 4 * a * c;
root1 = ( -b + sqrt(d)) / (2* a);
root2 = ( -b - sqrt(d)) / (2* a);
if ((p <= root1) && (root1 <= q))
return root1;
return root2;
}
int main (void) {
printf ("%f\n", find_root(1, -8, 15, 2, 4));
return 0;
}
That's the logic errors with your calculations of the roots.
Just keep in mind there are other issues with your code.
You need to ensure you actually call the function itself, your main as it stands does not.
It also wont produce a value within the p/q bounds, instead it will give you the first root if it's within those bounds, otherwise it'll give you the second root regardless of its value.
You may want to catch the situation where d is negative, since you don't want to take the square root of it:
a = 1000, b = 0, c = 1000: d <- -4,000,000
And, lastly, if your compiler is complaining about not being able to link sqrt (as per one of your comments), you'll probably find you can fix that by specifying the math library, something like:
gcc -o myprog myprog.c -lm
Your program starts at main by definition.
Your main function is not calling find_root but it should.
You need to compile with all warnings & debug info (gcc -Wall -Wextra -g) then use a debugger (gdb) to run your code step by step to understand the behavior of your program, so compile with
gcc -Wall -Wextra -g yoursource.c -lm -o yourbinary
or with
clang -Wall -Wextra -g yoursource.c -lm -o yourbinary
then learn how to use gdb (e.g. run gdb ./yourbinary ... and later ./yourbinary without a debugger)
Then you'll think and improve the source code and recompile it, and debug it again. And repeat that process till you are happy with your program.
BTW, you'll better end your printf format strings with \n or learn about fflush(3)
Don't forget to read the documentation of every function (like printf(3) ...) that you are calling.
You might want to give some arguments (thru your main(int argc, char**argv) ...) to your program. You could use atof(3) to convert them to a double
Read also about undefined behavior, which you should always avoid.
BTW, you can use any standard C compiler (and editor like emacs or gedit) for your homework, e.g. use gcc or clang on your Linux laptop (then use gdb ...). You don't need a specific seashell
Change this condition
if (root1<=q || root1>=p)
to
if (root1<=q && root1>=p)
otherwise if anyone of the conditions is satisfied, root1 will be returned and root2 will almost never be returned. Hope this fixes your problem.

double-precision numbers in inline assembly (GCC, IA-32)

I'm just starting to learn assembly and I want to round a floating-point value using a specified rounding mode. I've tried to implement this using fstcw, fldcw, and frndint.
Right now I get a couple of errors:
~ $ gc a02p
gcc -Wall -g a02p.c -o a02p
a02p.c: In function `roundD':
a02p.c:33: error: parse error before '[' token
a02p.c:21: warning: unused variable `mode'
~ $
I'm not sure if I am even doing this right at all. I don't want to use any predefined functions. I want to use GCC inline assembly.
This is the code:
#include <stdio.h>
#include <stdlib.h>
#define PRECISION 3
#define RND_CTL_BIT_SHIFT 10
// floating point rounding modes: IA-32 Manual, Vol. 1, p. 4-20
typedef enum {
ROUND_NEAREST_EVEN = 0 << RND_CTL_BIT_SHIFT,
ROUND_MINUS_INF = 1 << RND_CTL_BIT_SHIFT,
ROUND_PLUS_INF = 2 << RND_CTL_BIT_SHIFT,
ROUND_TOWARD_ZERO = 3 << RND_CTL_BIT_SHIFT
} RoundingMode;
double roundD (double n, RoundingMode roundingMode)
{
short c;
short mode = (( c & 0xf3ff) | (roundingMode));
asm("fldcw %[nIn] \n"
"fstcw %%eax \n" // not sure why i would need to store the CW
"fldcw %[modeIn] \n"
"frndint \n"
"fistp %[nOut] \n"
: [nOut] "=m" (n)
: [nIn] "m" (n)
: [modeIn] "m" (mode)
);
return n;
}
int main (int argc, char **argv)
{
double n = 0.0;
if (argc > 1)
n = atof(argv[1]);
printf("roundD even %.*f = %.*f\n",
PRECISION, n, PRECISION, roundD(n, ROUND_NEAREST_EVEN));
printf("roundD down %.*f = %.*f\n",
PRECISION, n, PRECISION, roundD(n, ROUND_MINUS_INF));
printf("roundD up %.*f = %.*f\n",
PRECISION, n, PRECISION, roundD(n, ROUND_PLUS_INF));
printf("roundD zero %.*f = %.*f\n",
PRECISION, n, PRECISION, roundD(n, ROUND_TOWARD_ZERO));
return 0;
}
Am I even remotely close to getting this right?
A better process is to write a simple function that rounds a floating point value. Next, instruct your compiler to print an assembly listing for the function. You may want to put the function in a separate file.
This process will show you the calling and exiting conventions used by the compiler. By placing the function in a separate file, you won't have to build other files. Also, it will give you the opportunity to replace the C language function with an assembly language function.
Although inline assembly is supported, I prefer to replace an entire function in assembly language and not use inline assembly (inline assembly isn't portable, so the source will have to be changed when porting to a different platform).
GCC's inline assembler syntax is arcane to say the least, and I do not claim to be an expert, but when I have used it I used this howto guide. In all examples all template markers are of the form %n where n is a number, rather then the %[ttt] form that you have used.
I also note that the line numbers reported in your error messages do not seem to correspond with the code you posted. So I wonder if they are in fact for this exact code?

absolute Value of double

I am trying write a function named absD that returns the absolute value of its argument.
I do not want to use any predefined functions. Right now i am getting a parse error when i try to compile it.
I would image all i would have to do to get the absolute value of a double is change the sign bit? this is what i have
#include <stdio.h>
#include <stdlib.h>
#define PRECISION 3
double absD (double n)
{
asm(" fld %eax \n"
" movl $0x7FFFFFFFFFFFFFFF, %eax \n"
" pop %eax \n"
);
return n;
}
int main (int argc, char **argv)
{
double n = 0.0;
printf("Absolute value\n");
if (argc > 1)
n = atof(argv[1]);
printf("abs(%.*f) = %.*f\n", PRECISION, n, PRECISION, absD(n));
return 0;
}
I fixed the curly brace..
the error i am getting is
~ $ gc a02
gcc -Wall -g a02.c -o a02
/tmp/ccl2H7rf.s: Assembler messages:
/tmp/ccl2H7rf.s:228: Error: suffix or operands invalid for `fld'
/tmp/ccl2H7rf.s:229: Error: missing or invalid immediate expression `0x7FFFFFFFF
FFFFFFF'
~ $
Do you need to do it in assembly? Is this a homework requirement, or are you looking for very high performance?
This doesn't use any predefined functions:
double absD(double n)
{
if (n < 0.0)
n = -n;
return n;
}
I'm no expert, but it looks like you're using ( to open the assembly block and } to end it. You probably should use one or the other, not both inconsistently.
asm(" fld %eax \n"
" movl $0x7FFFFFFFFFFFFFFF, %eax \n"
" pop %eax \n"
};
notice the curley bracket before the semicolon.
Depending on how you want to treat -0.0, you can use C99 / POSIX (2004)'s signbit() function.
#include <math.h>
double absD (double x)
{
if ( signbit(x) ) {
#ifdef NAIVE
return 0.0 - x;
#else
return x &= 0x7FFFFFFFFFFFFFFF;
#endif
} else {
return x;
}
}
But frankly if you're using Standard C Library (libc) atof and printf, I don't see why not using fabs() is desirable. As you can also do normal bit-twiddling in C.
Of course if you're using assembly, why not usefchs op anyhow?
You have errors in your assembly code, which the assembler gives you perfectly reasonable error messages about.
you can't load a floating point value directly from %eax -- the operand needs to be an address to load from
you can't have constant literals that don't fit in 32 bits.
The sign of a floating bit number is just the high bit, so all you need to to is clear the most significant bit.
If you must do this in assembly, then it seems to me that you would be better of using integer rather than floating point instructions. You can't do bitwise operations on floating point registers.
Also, there isn't any need to load the entire 8 byte value into any register, you could just as easily operate only on the high byte (or int) if your processor doesn't have 8 byte integer registers.
/tmp/ccl2H7rf.s:228: Error: suffix or
operands invalid for `fld'
fld needs the operand to be in memory. Put it in memory, ie the stack, and supply the address.
/tmp/ccl2H7rf.s:229: Error: missing or
invalid immediate expression
`0x7FFFFFFFF FFFFFFF'
EAX does not hold more than 32 bits. If you meant for this to be a floating point number, put it on the floating point stack with a load instruction, ie fld.

Resources