lldb and C code give different results for pow() - c

I have one variable, Npart which is an int and initialized to 64. Below is my code (test.c):
#include <math.h>
#include <stdio.h>
int Npart, N;
int main(){
Npart = 64;
N = (int) (pow(Npart/1., (1.0/3.0)));
printf("%d %d\n",Npart, N);
return 0;
};
which prints out 64 3, probably due to numerical precision issues. I compile it as follows:
gcc -g3 test.c -o test.x
If I try to debug using lldb, I try to calculate the value and print it in the command prompt, the following happens:
$ lldb ./test.x
(lldb) target create "./test.x"
Current executable set to './test.x' (x86_64).
(lldb) breakpoint set --file test.c --line 1
Breakpoint 1: where = test.x`main + 44 at test.c:8, address = 0x0000000100000f0c
(lldb) r
Process 20532 launched: './test.x' (x86_64)
Process 20532 stopped
* thread #1: tid = 0x5279e0, 0x0000000100000f0c test.x`main + 44 at test.c:8, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000f0c test.x`main + 44 at test.c:8
5
6 int main(){
7
-> 8 Npart = 64;
9
10 N = (int) (pow(Npart/1., (1.0/3.0)));
11 printf("%d %d\n",Npart, N);
(lldb) n
Process 20532 stopped
* thread #1: tid = 0x5279e0, 0x0000000100000f12 test.x`main + 50 at test.c:10, queue = 'com.apple.main-thread', stop reason = step over
frame #0: 0x0000000100000f12 test.x`main + 50 at test.c:10
7
8 Npart = 64;
9
-> 10 N = (int) (pow(Npart/1., (1.0/3.0)));
11 printf("%d %d\n",Npart, N);
12
13 return 0;
(lldb) n
Process 20532 stopped
* thread #1: tid = 0x5279e0, 0x0000000100000f4a test.x`main + 106 at test.c:11, queue = 'com.apple.main-thread', stop reason = step over
frame #0: 0x0000000100000f4a test.x`main + 106 at test.c:11
8 Npart = 64;
9
10 N = (int) (pow(Npart/1., (1.0/3.0)));
-> 11 printf("%d %d\n",Npart, N);
12
13 return 0;
14 };
(lldb) print Npart
(int) $0 = 64
(lldb) print (int)(pow(Npart/1.,(1.0/3.0)))
warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.
(int) $1 = 0
(lldb) print (int)(pow(64,1.0/3.0))
(int) $2 = 0
Why is lldb giving different results?
Edit: Clarified the question and provided a minimal verifiable example.

Your code calculates the cube root of 64, which should be 4.
The C code converts the return value to an integer by flooring it. The pow is usually implemented in some sort of Taylor polynomial or similar - this tends to be numerically inaccurate. The result on your computer seems to be a little less than 4.0, which when cast to int is truncated - the solution would be to use for example lround first instead:
N = lround(pow(Npart/1., (1.0/3.0)));
As for the lldb, the key is the text:
error: 'pow' has unknown return type; cast the call to its declared return type
i.e. it doesn't know the return type - thus the prototype - of the function. pow is declared as
double pow(double x, double y);
but since the only hint that lldb has about the return type is the cast you provided, lldb thinks the prototype is
int pow(int x, double y);
and that will lead into undefined behaviour - in practice, lldb thinks that the return value should be the int from the EAX register, hence 0 was printed, but the actual return value was in some floating point/SIMD register. Likewise, since the types of the arguments are not known either, you must not pass in an int.
Thus I guess you would get the proper value in the debugger with
print (double)(pow(64.0, 1.0/3.0))

Related

Cubes in Cuboids

Helo everybody,
I need a C program to calculate the minimum amount of cuboids of size A by B by C to house a N cubes of side length S, where 1 <= N <= pow(10, 9), 1 <= S <= min(A, B, C), 1 <= A, B, C <= 1000. I did the following:
#include <stdio.h>
int main() {
unsigned long long int cubenum, length, boxnum, a, b, c, cpb;
scanf("%llu %llu %llu %llu %llu", &cubenum, &length, &a, &b, &c); getchar();
// how many cubes per box?
cpb = a/length * b/length * c/length;
// how many boxes given the amount of cubes?
boxnum = (cubenum + (cpb - 1)) / cpb;
printf("%llu\n", boxnum);
return 0;
}
The following testcases are given:
testcase #1
stdin: 24 4 8 8 8
stdout: 3
testcase #2
stdin: 27 3 8 4 10
stdout: 5
I added the following testcases myself:
testcase #3
stdin: 1 1 1 1 1
stdout: 1
testcase #4
stdin: 1000000000 500 999 999 999
stdout: 1000000000
testcase #5
stdin: 1000000000 499 999 999 999
stdout: 125000000
testcase #6
stdin: 1000000000 2 999 999 999
stdout: 9
I compiled with Clang version 10.0.0-4ubuntu1. The given testcases passed correctly on my device, and the ones I added myself seem correct when doing the math manually, however upon submission my program was declared "wrong". Unfortunately, there isn't any feedback as to where, why, or how it failed. The compiler the jury uses is unknown, however my past experience tell me it's likely running Linux (I tried using a Windows specific library function). Therefore, I would like to know, are there any test cases where my code would fail that I haven't caught? Or are there other oversights that I have made?
Thank you for your time.
Side question:
The part I suspect I am getting wrong is here:
boxnum = (cubenum + (cpb - 1)) / cpb;
I have tried using ceil() in math.h, but it feels really hacky with the double casts and then back to unsigned long long int, but it does work on all the testcases. I had to compile with clang -lm main.c -o main instead of clang main.c -o main, but it did run. Could it be that the jury has a modified math.h lib? On a different program, I used sqrt() and pow() and they were both accepted as correct, which tells me either the problem isn't where I suspect it to be, or that the jury indeed does have a modified math.h lib. Or could it be something else?
The line
cpb = a/length * b/length * c/length;
is wrong because this expression is calculated from left to right and truncation may not work well for b and c.
For example, with this input
15 10 100 10 19
The formula will be calculated like
a/length * b/length * c/length
= 100/10 * 10/10 * 19/10
= 10 * 10 / 10 * 19 / 10
= 100 / 10 * 19 / 10
= 10 * 19 / 10
= 190 / 10
= 19
Therefore, your program will output 1 because the required 15 cubes can be covered by 19 cubes while the correct output is 2 because actually only 10 cubes can be created from one box.
Try this:
cpb = (a/length) * (b/length) * (c/length);

How to read and change value from memory in Linux?

The code inside main.c
#include <stdio.h>
#include <unistd.h>
int main() {
int c_variable = 0; // the target
for(int x = 0; x < 100; x++) {
c_variable += 5; // increase by 5 to change the value of the int
printf("%i\n", c_variable); // print current value
sleep(8); // sleep so I have time to scan memory
}
return 0;
}
What I am trying to achieve is to read the integer c_variable and then to modify it inside another .c program. I am on linux so I did ps -A | grep main and got the PID of the running program. I then did sudo scanmem PID and entered the current value of c_variable a few times. I was left with three memory addresses and executing the command set 500 changed the value the program printed, effectively changing the memory address' value to 500 instead of 35 or whatever the program was currently at. I then executed the following code
#include <stdio.h>
int main() {
const long unsigned addr = 0x772d85fa1008; // one of the three addresses from scanmem
printf("%lu\n", addr);
return 0;
}
but I got some random long string of numbers, not the current number. The tutorials and answers I have read on how to read and write memory on linux does not have to use long unsigned but can use char* or just int* instead. My memory address seems to be a bit long, I have not see memory addresses that long before. Anyhow, how do I read and write the memory address of the integer c_variable?
Edit: the output of scanmem looks something like this
info: we currently have 3 matches.
3> list
[ 0] 7771ff64b090, 6 + 1e090, stack, 20, [I64 I32 I16 I8 ]
[ 1] 7771ff64b5d8, 6 + 1e5d8, stack, 20, [I64 I32 I16 I8 ]
[ 2] 7771ff64b698, 6 + 1e698, stack, 20, [I32 I16 I8 ]
3> set 50
info: setting *0x7771ff64b090 to 0x32...
info: setting *0x7771ff64b5d8 to 0x32...
info: setting *0x7771ff64b698 to 0x32...
output
...
150
155
160
165
170
175
55
60
65
...
You're printing the actual address number, but in in decimal notation, not what is at the address.
const int *addr = (int *) 0x772d85fa1008;
printf("%d\n", *addr);
You have to declare addr as a pointer type. More specifically a pointer to an integer. Its value (0x772d85fa1008) holds the address of the integer.
Then, in the printf call you dereference it to obtain the actual integer stored at the address.
Although in practice I can't vouch for whether this is going to work, since memory in modern operating systems isn't as simple as you make it out to be. But I don't have enough knowledge to assess that.
Processes running under Linux generally have their own virtualized memory space. If you want to access memory space of another process, arrangements have been made in the Linux API, see shmctl, shmget, shmat, shmdt.

Why can't I insert a breakpoint here (I might add all my friends can, and I see no other way to solve this)

(gdb) list 1,20
1 int swap_n_add(int *xp, int *yp)
2 {
3 int x = *xp;
4 int y = *yp;
5
6 *xp = y;
7 *yp = x;
8 return x + y;
9 }
10
11 int main() {
12 int a1 = 534;
13 int a2 = 1057;
14 int sum = swap_n_add(&a1, &a2);
15 int diff = a1 - a2;
16
17 return sum * diff;
18 }
(gdb) b 18
No line 18 in file "swap_n_add.c".
I want to check the value main returns, so I put a breakpoint at 18 to inspect the register there (info register). But it says that line doesn't exist, despite it... saying it does exist. And my friends with identical code can put it there.
I would question the previous setup steps that you haven't shown. If your friend's are able to set a breakpoint there and you are not, there is probably something you did wrong. (assuming everyone is using the same versions of all the tools)
with gdb version 7.4-2012.04 for Ubuntu and gcc 4.6.3 I can see and set a break point at the line in question:
> gcc -Wall -g file.c <-- compile with -g for debug symbols
> gdb a.out <-- run against the executable
This GDB was configured as "x86_64-linux-gnu". <-- make sure it was configured for
For bug reporting instructions, please see: your architecture
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/mike/C/a.out...done. <-- and that your file loads symbols
(gdb) line 22, 39
22 int swap_n_add(int *xp, int *yp) <-- mine are different because I have a bunch
23 { of #include's in my test file
24 int x = *xp;
25 int y = *yp;
26
27 *xp = y;
28 *yp = x;
29 return x + y;
30 }
31
32 int main() {
33 int a1 = 534;
34 int a2 = 1057;
35 int sum = swap_n_add(&a1, &a2);
36 int diff = a1 - a2;
37
38 return sum * diff;
39 }
(gdb) b 39
Breakpoint 1 at 0x400530: file file.c, line 39.
Note that if I pick a line outside of the file, say.. 75, it gives you a message about "no line x in file":
(gdb) b 75
No line 75 in the current file.
Make breakpoint pending on future shared library load? (y or [n])
If you're seeing this it's worth double checking your line numbers, it's possible you mis-counted.
If you want to see the value of the return (sum * diff) you can always set that to a local variable before returning and break on the return.
This may be compiler/debugger-specific. There may be no debug information generated for the closing brace.
Also, if you have optimization enabled, it can make it hard or impossible to put breakpoints at some locations. Try removing the -O parameter to gcc, if you use it.
If it still doesn't help, assign the return value to a new variable and return that variable instead.
Alternatively, you could just switch to the disassembly, put a breakpoint on the ret instruction of main() (the instruction that does function return on x86) and examine the returned value in the CPU registers (should be in eax on x86).

Floating point formatting in LLDB (debugging C++)

Given a double d, I can print it,
(lldb) expr d
(double) $2 = 3.05658e-08
Is there a way to print more digits of d, such as
printf("%.15f", d) ?
Version of LLDB in question is LLDB-112.2, supplied with OS X 10.7.4
EDIT: Using
(lldb) expr (int) printf("%.15f", d)
results in the process being killed, with a
LLVM ERROR: Internal relocations not supported.
error message.
lldb-112.2 is a little old at this point (I think it is about six or seven months old); checking it against the Xcode 4.5 lldb (lldb-167 or so), it looks like it works correctly now.
0.000000030565830
Process 77907 stopped
* thread #1: tid = 0x1c03, 0x0000000100000f34 a.out`main + 52 at a.c:6, stop reason = breakpoint 1.1
#0: 0x0000000100000f34 a.out`main + 52 at a.c:6
3 {
4 double d = .00000003056583;
5 printf ("%.15f\n", d);
-> 6 return 5;
7 }
(lldb) p d
(double) $0 = 3.05658e-08
(lldb) expr (int)printf("%.15f\n", d)
(int) $1 = 18
0.000000030565830
Have you tried:
printf("%.15f", d)
?

SSE shifting integers

I'm trying to understand how shifting with SSE works, but I don't understand the output gdb gives me. Using SSE4 I have a 128bit vector holding 8 16bit unsigned integers (using uint16_t). Then I use the intrinsic _mm_cmpgt_epi16 to compare them against some value, this function puts in all 0 or 1 bits into the bits used to store the ints. So far so good, using gdb I get:
(gdb) p/t sse_res[0]
$3 = {1111111111111111111111111111111111111111111111110000000000000000, 1111111111111111111111111111111111111111111111110000000000000000}
Then I would like to shift them to the right (is that correct?) so I just get a numerical value of 1 in case it's true. GDB then gives me an output which I don't understand:
(gdb) p/t shifted
$4 = {11101000000000010010000000000000110000000000000000011, 100111000000000001011000000000001001000000000000001111}
It's not even of the same length as the first, why is this? Just to try it out I used the following intrinsic to shift it one bit to the right:
shifted = _mm_srli_epi16(sse_array[i], 1);
I expected it to shift in just one zero at the right end of every 16bit block.
Update:
I wrote a small example to test the thing with the bitmask, it works fine, but I still don't understand gdbs behavior:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <tmmintrin.h>
#include <smmintrin.h>
void print128_num(__m128i vector)
{
uint16_t *values = (uint16_t*) &vector;
printf("Numerical: %i %i %i %i %i %i %i %i \n",
values[0], values[1], values[2], values[3], values[4], values[5],
values[6], values[7]);
}
int main (int argc, char **argv)
{
uint16_t nums[] = {1, 57, 33, 22, 88, 99, 9, 73};
__m128i *nums_sse = (__m128i*)(&nums);
print128_num(*nums_sse);
// vector of 42
__m128i mm42 = _mm_set1_epi16(42);
__m128i sse_res = _mm_cmpgt_epi16(*nums_sse, mm42);
printf("Result of the comparison\n");
print128_num(sse_res);
// bitmask
__m128i mask = _mm_set1_epi16(1);
__m128i finally = _mm_and_si128(sse_res, mask);
printf("Result of the masking\n");
print128_num(finally);
uint16_t* sse_ptr = (uint16_t*)(&finally);
uint32_t result = sse_ptr[0] + sse_ptr[1] + sse_ptr[2] + sse_ptr[3]
+ sse_ptr[4] + sse_ptr[5] + sse_ptr[6] + sse_ptr[7];
printf("Result: %i numbers greater 42\n", result);
return 0;
}
Breakpoint 1, main (argc=1, argv=0x7fff5fbff3b0) at example_comp.c:44
44 printf("Result: %i numbers greater 42\n", result);
(gdb) p/t sse_res
$1 = {11111111111111110000000000000000, 1111111111111111000000000000000011111111111111111111111111111111}
(gdb) p/t mask
$2 = {1000000000000000100000000000000010000000000000001, 1000000000000000100000000000000010000000000000001}
(gdb) p/t finally
$3 = {10000000000000000, 1000000000000000000000000000000010000000000000001}
(gdb) p result
$4 = 4
(gdb)
My gdb version: GNU gdb 6.3.50-20050815 (Apple version gdb-1472) (Wed Jul 21 10:53:12 UTC 2010)
Compiler flags: -Wall -g -O0 -mssse3 -msse4 -std=c99
I don't understand exactly what you're trying to do here, but maybe you can clarify it for us.
So, you have 8 signed integers packed in each of two variables, which you test for greater than. The result looks like it shows that the first 3 are greater, the next is not, the next 3 are greater, the last is not. (_mm_cmpgt_epi16 assumes signed integers in the reference I found.)
Then you want to tell if "it" is true, but I'm not sure what you mean by that. Do you mean they are all greater? (If so, then you could just compare the result against MAX_VALUE or -1 or something like that.)
But the last step is to shift some data to the right piecewise. Notice that is not the same variable as sse_res[0]. Were you expecting to shift that one instead?
Without knowing what was in the data before shifting, we can't tell if it worked correctly, but I assume that gdb is omitting the leading zeroes in its output, which would explain the shorter result.
0000000000011101 29 was 58 or 59
0000000000100100 36 was 72 or 73
0000000000011000 24 was 48 or 49
0000000000000011 3 was 6 or 7
0000000000100111 39 was 78 or 79
0000000000010110 22 was 44 or 45
0000000000100100 36 was 72 or 73
0000000000001111 15 was 30 or 31
Do these numbers look familiar?
Update:
Thanks for the updated code. It looks the integers are packed in the reverse order, and the leading zeroes left off in the gdb output.

Resources