0

I have been Googling this for days now and I am lost. So doing CS50 online and can't seem to get a handle on this rounding of numbers. My program is messing up multiplying floats like 2.10 with integers like 100 it would output 209.xxxxxxxx

Now like I say I have read countless posts on that I should use ceilf and include but I am getting an error

greedy.c:(.text+0x74): undefined reference to `ceilf' collect2: error: ld returned 1 exit status make: *** [greedy] Error 1 adam@beethoven:~/projects/atom/edx/pSet1/greedy$

I have seen the posts about -lm and a certain file but if I am honest I don't understand what it means.

I am in no way looking for an outright solution, just guidance in improving.

Here is my code, probably not as streamlined as some would like but I am back to basics here ;)

#include <stdio.h>
#include <math.h>

int main() {
  // Initialize Variables
  int coinsTotal = 0,
      quarter = 25,
      dime = 10,
      nickel = 5,
      penny = 1,
      cents;
  float changeDue;

  do {
    printf("How much change are you owed? (Format = 0.00)($): ");
    scanf("%f", &changeDue );
    // Convert to cents
    cents = changeDue * 100;
  } while(cents <= 0);

  while (cents >= quarter) {
    cents = cents - quarter;
    coinsTotal = coinsTotal + 1;
  } if (cents == 0) {
      printf("The miminum number of coins is: %d\n", coinsTotal);
  } else {
      while (cents >= dime) {
        cents - dime;
        coinsTotal = coinsTotal + 1;
      } if (cents == 0) {
          printf("The minimum number of coins is: %d\n", coinsTotal);
      } else {
          while (cents >= nickel) {
            cents = cents - nickel;
            coinsTotal = coinsTotal + 1;
          } if (cents == 0) {
              printf("The minimum number of coins is: %d\n", coinsTotal);
          } else {
              while (cents >= penny) {
                cents = cents - penny;
                coinsTotal = coinsTotal + 1;
              } if (cents == 0) {
                  printf("The minimum number of coins is: %d\n", coinsTotal);
                }
        }
      }
    }
}

Basically it should work out the minimum number of coins needed to make a given amount. It works in most cases until the floats mess up. Excuse the notes I like to write what I did so I learn better.

Update Tried to compile with GCC using -lm but still failed. adam@beethoven:~/projects/atom/edx/pSet1/greedy$ gcc -o foo -lm greedy.c /tmp/cc3qHAK7.o: In function main': greedy.c:(.text+0x6e): undefined reference toceilf' collect2: error: ld returned 1 exit status adam@beethoven:~/projects/atom/edx/pSet1/greedy$

SOLUTION Instead of using the make command I used gcc and added the -lm flag At the end of the command gcc -o foo greedy.c -lm

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Do you know what a MCVE is? – Amit Sep 02 '15 at 21:02
  • 1
    Hi, Amit I didn't know what it is. I have Googled it and found the page on this site. I appreciate you pointing it out and I will be editing my post accordingly. A – Adam 'Sacki' Sackfield Sep 02 '15 at 21:06
  • 2
    Good, you're a model citizen :-) – Amit Sep 02 '15 at 21:10
  • why not just parse the input string by hand so that you don't have to use any math functions to do something as simple as reading a string such as "2.10" and converting it to the number 210? – mwag Sep 02 '15 at 21:11
  • Guidance: 1) If code is to use money in floating point, use `double`. 2) whenever converting floating point money to `int`, use `round()` as in `cents = round(changeDue * 100);` – chux - Reinstate Monica Sep 02 '15 at 21:23
  • @mwag - That isn't the aim of the program, it needs to get it as int first to do some more work. – Adam 'Sacki' Sackfield Sep 02 '15 at 21:28
  • @chux - This is another function plagued with the same misfortune as ceilf. – Adam 'Sacki' Sackfield Sep 02 '15 at 21:28
  • @Adam Disagree. What is an example misfortune caused by `round()` usage? – chux - Reinstate Monica Sep 02 '15 at 21:31
  • @chux - Basically I am doing this pset - http://cdn.cs50.net/2015/x/psets/1/pset1/pset1.html#time_for_change. Now when an input of say '1.00' is multiplied by '100' I get '100' as an answer correct I know. Say I enter '2.10' and do the same I get '209.xxxxxxx' rather than the actual '210'. This is why I went for 'MATH.H' and wherein the issue lies. I Have it narrowed down as answer 1 will show. – Adam 'Sacki' Sackfield Sep 02 '15 at 21:36
  • Your reference say "And be careful to round and not truncate your pennies!". When you get '209.xxxxxxx' you are more like getting `209.9xxxxxx'`. `double round(double x)` from `` solves this issue as it returns `210.0`. Still maintain it is not "plagued with the same misfortune as ceilf" and looking for your example of how `round(double)` is an issue. OTOH - I do see `round()` in `` has the same problem in that you need to link the math library. Agree on that. My guidance was for your next issues as you requested "just guidance in improving" – chux - Reinstate Monica Sep 02 '15 at 21:43
  • @Adam'Sacki'Sackfield uh yea, I get it-- it seems you either didn't read or didn't understand my comment, which implicitly means that you would use scanf() to scan a STRING, not a float, and then convert that string to int. – mwag Sep 02 '15 at 21:53

2 Answers2

2

I have seen the posts about -lm and a certain file but if I am honest I don't understand what it means.

You have to link to the math library to fix the error. Math functions implementations are usually put as a separate library, the math library. If you use gcc add -lm to the linker command.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • Hi, This is where I get stuck, I guess 'gcc' is like 'cc' that is used when I use the 'make' command to compile my 'c'. I literally don't have a clue what the -lm does and what an equivalent would be with the make command. Perhaps I can set up GCC. – Adam 'Sacki' Sackfield Sep 02 '15 at 21:10
  • 1
    Adding `-lm` says "please link against a library called libm ". If you are using a Makefile, find the command used to generate the final binary and add `-lm` to it. – ouah Sep 02 '15 at 21:11
  • 1
    @Adam'Sacki'Sackfield Since you're using a makefile, you probably want to add it to `LDFLAGS` at the beginning of your makefile or just use `make LDFLAGS=-lm greedy`, assuming your `cc` line in the makefile has `$(LDFLAGS)` listed at the end of the line. If it isn't listed on the `cc` line, you can either add `$(LDFLAGS)` at the end of the `cc` line, or you can just hardcode `-lm` itself at the end of the line in place of `$(LDFLAGS)`. `$(LDFLAGS)` is more flexible, however, since it lets you list more than one library, e.g. `make LDFLAGS='-lmylib -lXt -lX11 -lm` –  Sep 02 '15 at 21:16
  • 1
    You can use the following mysterious invocation: `make myprog LDLIBS=-lm` (substitute `myprog` for whatever you usually make). – rici Sep 02 '15 at 21:18
  • 1
    @ChronoKitsune: LDLIBS, not LDFLAGS. LDFLAGS comes too early in the command line. – rici Sep 02 '15 at 21:18
  • @rici `LDFLAGS` is more common - many skeleton makefiles (and default build rules) use e.g. `$(CPPFLAGS)`, `$(CFLAGS)` and `$(LDFLAGS)`. I don't think I've ever seen one use `LDLIBS`. – Alnitak Sep 02 '15 at 21:20
  • Wow thanks peeps. I will try these suggestions shortly and see how it goes. Just for reference I tried what @ouah said and went and compiled it with GCC after some Googling but I got the same error. I will update my post with the command I used. I will also come back once I have tried all other suggestions. – Adam 'Sacki' Sackfield Sep 02 '15 at 21:24
  • @alnitak the default rules for both gmake and bsdmake use LDLIBS. It is very standard. – rici Sep 02 '15 at 21:26
  • 1
    @Adam'Sacki'Sackfield `-lm` has to be added at the end of the compilation/linking line, not in the middle as you did in your edit. – ouah Sep 02 '15 at 21:36
  • 1
    @ouah - Oh man that is awesome, it now compiles. Still wrong but that's on me to tinker with the math functions that now work. Much appreciated. – Adam 'Sacki' Sackfield Sep 02 '15 at 21:39
  • @Alnitak: Yep, it was added to FreeBSD's `sys.mk` file 19 years and 10 months ago (https://svnweb.freebsd.org/base/head/share/mk/sys.mk?r1=10028&r2=11613), so if you haven't looked in 20 years, you could have missed it. With all due respect though, that does rather condition your statement: "I don't think I've ever seen one." :) – rici Sep 02 '15 at 23:25
0

I presume you want to round floating numbers to the nearest integer. ceilf is not doing that, it is rounding up. You can use this macro for rounding to nearest long when possible:

#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))

Also, you get a linking error because you don't link with the math library. For example use :

gcc greedy.c -lm -o greedy
Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
  • I want to round up to 2 decimal places. – Adam 'Sacki' Sackfield Sep 02 '15 at 21:29
  • 2
    Note: `round(double)` from does a better job than this define. The define has trouble with cases like the number before 0.5 and whole numbers exactly representably as `long`, but not `double`, and some others near there. It _does_ have the advantage that the math library is not needed, which OP has trouble linking. – chux - Reinstate Monica Sep 02 '15 at 21:52