So the program does work to a degree however you have a typo and there's no such system function named
praintf() instead it would be
printf().
Note also that in your if statement to test that the fork() failed, you have your printf() statements and they don't make a lot of sense, because you're not taking in any input from the console, by using any of getchar or scanf.
If you compile that using the -ggdb flag and use GDB to step through it, you get a random number and always get the SAME random number, because merely using rand() without selecting a randomized seed, srand() (suggest using time and date for your seed) then you end up getting a deterministic result; hence always that same number.
No process is distinctly sending a signal, the system is doing this because information has been placed into the pipe. The CHILD happens to be the one exciting this, the child is when you get pid of zero, therefore the logic validating that pid is zero is the one the writes to the pipe and the PARENT receives a return from the fork() giving it the child's PID, which is your else case.
The code works. I'd suggest adding a few printf() statements to see what the value of num1 is at the start of the program, see what the descriptor values for fd[2] are; you can also print those out, and then put some printf() statements in the if-else cases to show your progress of reading and writing from/to the pipe, in those cases ALL printf's will show up at your main console, so ensure that you place something distinctive in there such as "PARENT: Read %d from pipe", or "CHILD: Wrote %d to pipe" to clarify things for you.
I have a number of blog entries on these subjects, they are a mile further than what you're doing here, but if you wish to peruse them, they are here:
Using PIPES for Interprocess Communications
Select(2) and why I use it
Creating a daemon to launch and monitor your processes
How to kill those zombies