Go Back   MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Oct 16, 2010, 08:46 PM   #1
bahlquist
macrumors member
 
Join Date: Oct 2010
Trouble with output of float values using NSLog

(This is a restatement of a problem brought up in a previous thread.) This program outputs two numbers each time a button is pushed. The first number is random. The second number should be 1 greater than the first. However, this is not the case (as can be seen by pushing the button more than once).

BATester.h:

Code:
#import <Cocoa/Cocoa.h>

@interface BATester : NSObject {
}
- (IBAction)button:(id)sender;
@end



BATester.m:

Code:
#import "BATester.h"

@implementation BATester
- (IBAction)button:(id)sender {
	NSNumber* theNumb;
	theNumb=[[NSNumber numberWithFloat:rand()] retain]; 
	NSLog(@"%f and %f", [theNumb floatValue],([theNumb floatValue]+1));
}
@end
Here is my output:

Code:
[Session started at 2010-10-16 18:32:35 -0700.]
2010-10-16 18:32:42.181 Tester[419:10b] 16807.000000 and 16808.000000
2010-10-16 18:32:43.275 Tester[419:10b] 282475264.000000 and 282475264.000000
2010-10-16 18:32:45.762 Tester[419:10b] 1622650112.000000 and 1622650112.000000
2010-10-16 18:43:34.338 Tester[419:10b] 984943680.000000 and 984943680.000000


The first time the button is pushed, no problem, but all subsequent pushes print out the same number twice. What is going on?

(If you are worried about memory leaks, please address this issue in my post entitled "Memory leaks".)
bahlquist is offline   0 Reply With Quote
Old Oct 16, 2010, 09:24 PM   #2
chown33
macrumors 603
 
Join Date: Aug 2009
The cases where it fails to add 1 are all because you've exceed the precision (number of significant digits) of a float.

Change the type to double (i.e. doubleValue) and it will work.

Better still, use the correct simple type, which is int (the type returned by rand()), and you can eliminate most of the pointless code, including eliminating memory leaks.

Code:
- (IBAction)button:(id)sender {
	int number = rand();
	NSLog(@"%d and %d", number, number+1);
}
The basic problem here is that you're applying brute force and ignorance in order to obtain immediately gratifying but ultimately vacuous results. What you should be doing instead is learning fundamentals like different integer and floating-point types, and how each one works in different circumstances.

I've already said this once, but I'll repeat it: you should be learning from a book.

Almost any book will have adequate guidance and will introduce things at a suitable time. All that's happening now is you're flailing around in deep water, with little or no actual knowledge of what you're doing or why. In short, you're drowning yourself when you should be taking swimming lessons.
chown33 is offline   0 Reply With Quote
Old Oct 16, 2010, 09:47 PM   #3
lee1210
macrumors 68040
 
lee1210's Avatar
 
Join Date: Jan 2005
Location: Dallas, TX
I will add that float is very, very rarely the right type to use for anything, ever. It's 2010. We have multi-ghz 64-bit CPUs and GBs of RAM in almost every machine. Saving 4 bytes and sacrificing precision is not generally a good plan unless you are developing in an environment where the computational demands of double precision math are too high (or unavailable), or the memory requirements are so tight that you can't afford the 4 bytes. If you are in that situation, you know it. If you're not, use double.

-Lee
lee1210 is offline   0 Reply With Quote
Old Oct 16, 2010, 09:58 PM   #4
bahlquist
Thread Starter
macrumors member
 
Join Date: Oct 2010
Quote:
Originally Posted by chown33 View Post
The cases where it fails to add 1 are all because you've exceed the precision (number of significant digits) of a float.

Change the type to double (i.e. doubleValue) and it will work.
Yes, that fixes this problem. So, when I attempt to do the operation "+", and I exceed the precision, why does it return the number it does? It is not choosing the first operand ([numb floatValue]) to return by default, for I switched the order around ((1+ [numb floatValue]) instead of ([numb floatValue]+1)) and I got the same result. I couldn't find an answer to this in my book.
bahlquist is offline   0 Reply With Quote
Old Oct 16, 2010, 11:35 PM   #5
lee1210
macrumors 68040
 
lee1210's Avatar
 
Join Date: Jan 2005
Location: Dallas, TX
If you really want to, you can research IEEE-754 32-bit floating point representations, and see what the representations of these values will be. Once you have that, you can look into how addition is performed on these. The ultimate result will be that the values are adjusted such that the exponent is the same, so simple addition can be performed on the significand. When 1 is adjusted to have the same exponent as your very large numbers, it will be rounded to 0. This yields the behavior you observe.

Using double would help this situation, but not remedy it completely. Binary math with floating points is inherently imprecise. That is why, as in this case, that fixed point math (which can be done exactly in binary) should be used when at all possible.

-Lee
lee1210 is offline   0 Reply With Quote
Old Oct 17, 2010, 04:40 AM   #6
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
I see this all the time, beginners using "float" instead of "double", and I am really wondering why. Is there any book recommending this (in which case we should add it to a list of "books never to be opened"), or is there some teacher advising you to use float (in which case he or she should be slapped) or did you just use the first one that came to mind without any clue about the difference?

To the OP: Google for "N1256" which should find the document "N1256.pdf" which contains the latest free draft of the C99 language standard. Then search for "float".

Finally, saving two keystrokes to write "theNumb" instead of "theNumber" is really a bad trade-off. numb = "deprived of the power of sensation", number = "arithmetic value, quantity or amount". Two letters saved, meaning of the word destroyed.

Finally finally, you realise your code has a memory leak?

Last edited by gnasher729; Oct 17, 2010 at 04:53 AM.
gnasher729 is offline   0 Reply With Quote
Old Oct 17, 2010, 12:02 PM   #7
jared_kipe
macrumors 68030
 
jared_kipe's Avatar
 
Join Date: Dec 2003
Location: Seattle
Send a message via AIM to jared_kipe
Quote:
Originally Posted by gnasher729 View Post
Finally finally, you realise your code has a memory leak?
A particularly pointless memory leak as he used +numberWithFloat: then retain instead of just letting it get autoreleased later.

Floats are still used. Specifically places where you need a whole lot of them (like in large arrays say in OpenGL), or places where you won't notice the lack in precision (CGFloat on iOS and i386 MacOS, while x86_64 MacOS CGFloats are double precision (64bit floats))
jared_kipe is offline   0 Reply With Quote
Old Oct 17, 2010, 12:48 PM   #8
chown33
macrumors 603
 
Join Date: Aug 2009
Quote:
Originally Posted by bahlquist View Post
It is not choosing the first operand ([numb floatValue]) to return by default, for I switched the order around ((1+ [numb floatValue]) instead of ([numb floatValue]+1)) and I got the same result.
Operand order has no effect in this case. The arithmetic expression only has a single operator, so precedence plays no part.

Quote:
I couldn't find an answer to this in my book.
Which book? Title, author, edition.

Many beginner books won't explain the precision limits of the float type. Instead, they would just use double and avoid explaining anything.

Is this random-number program an exercise in your book? Does it tell you to use NSNumber, or did you decide that yourself? How did the choice of 'float' come about?
chown33 is offline   0 Reply With Quote
Old Oct 17, 2010, 02:16 PM   #9
bahlquist
Thread Starter
macrumors member
 
Join Date: Oct 2010
Quote:
Originally Posted by lee1210 View Post
If you really want to, you can research IEEE-754 32-bit floating point representations, and see what the representations of these values will be. Once you have that, you can look into how addition is performed on these. The ultimate result will be that the values are adjusted such that the exponent is the same, so simple addition can be performed on the significand. When 1 is adjusted to have the same exponent as your very large numbers, it will be rounded to 0. This yields the behavior you observe.

Using double would help this situation, but not remedy it completely. Binary math with floating points is inherently imprecise. That is why, as in this case, that fixed point math (which can be done exactly in binary) should be used when at all possible.

-Lee
Thank you for your concise and helpful answer.
bahlquist is offline   0 Reply With Quote
Old Oct 17, 2010, 03:28 PM   #10
lee1210
macrumors 68040
 
lee1210's Avatar
 
Join Date: Jan 2005
Location: Dallas, TX
Quote:
Originally Posted by bahlquist View Post
Thank you for your concise and helpful answer.
Sure. Because I was feeling bored and wanted to write some code that wasn't work-related:
Code:
#include <stdio.h>
#include <inttypes.h>

void print_float_info(float);
void print_sig(uint32_t);

int main(int argc, char *argv) {
  float a,b,c,d,one;
  uint32_t *show_a,*show_b,*show_c,*show_d,*show_one;
  one = 1.f;
  a = 16807.f;
  b = 282475264.f;
  c = 1622650112.f;
  d = 984943680.f;
  show_a=(uint32_t *)&a;
  show_b=(uint32_t *)&b;
  show_c=(uint32_t *)&c;
  show_d=(uint32_t *)&d;
  show_one=(uint32_t *)&one;
  printf("a: %X\tb: %X\tc: %X\td: %X\tone: %X\n",*show_a,*show_b,*show_c,*show_d,*show_one);
  print_float_info(a);
  print_float_info(b);
  print_float_info(c);
  print_float_info(d);
  print_float_info(one);
}

void print_float_info(float a) {
  uint32_t *show_a;
  uint32_t significand;
  int32_t exponent;
  char sign;
  show_a = (uint32_t *)&a;
  sign = (0x80000000 & *show_a)?'-':'+'; 
  exponent = ((0x7F800000 & *show_a) >> 23) - 127;
  significand = (0x7FFFFF & *show_a);
  printf("%f decimal intrepretation. Sign: %c Exp: %d Sig: ",a,sign,exponent);
  print_sig(significand);
  printf("\n");
}

void print_sig(uint32_t a) {
  int pos;
  uint32_t bits[23] = {0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x100,0x200,0x400,0x800,0x1000,0x2000,0x4000,0x8000,0x10000,0x20000,0x40000,0x80000,0x100000,0x200000,0x400000};
  printf("1.");
  for(pos=22;pos>=0;pos--) {
    printf("%c",(bits[pos]&a)?'1':'0');
  }
}
This doesn't deal with 0, subnormals, infinities, etc. but it does pull apart a float, show you the components, and it might help you see why the 1 issue might be problematic. Basically if the exponent is greater than 23, that means that there are "trailing zeros" past what's actually stored in the significand past which the binary point will get moved. That means that there would not be enough precision to store something in the bit just left of the binary point.

In fact, it's quite possible that the float values you were getting were already very rounded from what actually came back from rand(), but if you weren't displaying what came back from rand you might not have known about it.

jared_kipe pointed out a few times floats get used. These examples are APIs where the designer (who knows a lot more than most of us) has made a specific decision about the sacrifice being made. Until you're at that level, you should never actually need float.

-Lee

Last edited by lee1210; Oct 17, 2010 at 03:38 PM.
lee1210 is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Similar Threads
thread Thread Starter Forum Replies Last Post
Resolved: NSLog to Serial port? xArtx iPhone/iPad Programming 11 Oct 17, 2013 10:03 PM
Are meeting reminders supposed to float? Steviejobz iOS 7 1 Sep 18, 2013 03:04 PM
Disable NSLog spilakalb iPhone/iPad Programming 3 Oct 1, 2012 03:16 PM
using a float to display height animefx iPhone/iPad Programming 5 Jul 30, 2012 12:09 PM
Any NSlog configuration possible? xArtx iPhone/iPad Programming 5 Jul 5, 2012 01:50 AM

Forum Jump

All times are GMT -5. The time now is 01:52 PM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps