11

Is there a safe way to "convert" a CGFloat to a NSNumber ?

NSNumber has the numberWithFloat: and numberWithDouble: methods but CGFloat being defined as float or double depending on the platform, it seems risky to use either one of them.

Or is numberWithDouble: safe to use with a CGFloat, as it is the one with the more precision ?

Guillaume Algis
  • 10,705
  • 6
  • 44
  • 72
  • 3
    If you have a enough high compiler version, just write *@(myNumber)* and it will be resolved at compile time. However you can safely call *[NSNumber numberWithDouble: myNumber]*, if *CGFloat* is defined to be double you do it correctly, it *CGFloat* is defined to be float you still haven't lost any precision. – Ramy Al Zuhouri Jun 12 '13 at 14:20
  • safe? can you explain? – Lithu T.V Jun 12 '13 at 14:25
  • 2
    safe as "without precision loss". Is this why I was downvoted ? – Guillaume Algis Jun 12 '13 at 14:28
  • 1
    I down voted it because IMHO you are just over thinking. C is full of functions that handle doubles, not overridden to work also with floats just because if you pass a float instead of a double **nothing harmful can happen**. It will just be implicitly casted to a double, which uses extra precision. – Ramy Al Zuhouri Jun 12 '13 at 14:36
  • I'm over thinking it because my code will handle real money. So better be safe (pun not intended) than sorry. (and I also don't think this was worth a downvote, but eh...) – Guillaume Algis Jun 12 '13 at 14:44
  • This casting wastes cycles, and can be significant in code that does lots of floating point arithmetic. In terms of math functions, I recommend using `tgmath.h` and letting the compiler choose the right function for you at compile time. – ipmcc Jun 12 '13 at 14:45
  • 3
    If you're handling money, you may wish to consider using a fixed point or decimal representation. See `NSDecimal` and `NSDecimalNumber`. – ipmcc Jun 12 '13 at 14:46
  • For which device support you are bulding this app? – Lithu T.V Jun 12 '13 at 14:47
  • Don't use floating point for real money. – Arkku Jun 12 '13 at 14:51
  • @LithuT.V iPad but I didn't want it to be relevant, I wanted portable-ish code. @ipmcc already using these, but wanted a convenient way to init them from `CGFloat`. – Guillaume Algis Jun 12 '13 at 14:52
  • well iphone is a 32 bit device .CGFloat is a regular float on 32-bit systems and a double on 64-bit systems.thats why i asked – Lithu T.V Jun 12 '13 at 14:55

2 Answers2

33

I believe @ NSNumber literal is good enough

@(myCGFloat)

Read more here: http://clang.llvm.org/docs/ObjectiveCLiterals.html

Lukas Kukacka
  • 7,604
  • 2
  • 25
  • 50
24

This is how I handled it:

@interface NSNumber (CGFloatAdditions)

+ (NSNumber*)numberWithCGFloat: (CGFloat)value;
- (CGFloat)CGFloatValue;

@end

@implementation NSNumber (CGFloatAdditions)

+ (NSNumber*)numberWithCGFloat: (CGFloat)value
{
#if CGFLOAT_IS_DOUBLE
    return [NSNumber numberWithDouble: (double)value];
#else
    return [NSNumber numberWithFloat: value];
#endif
}

- (CGFloat)CGFloatValue
{
#if CGFLOAT_IS_DOUBLE
    return [self doubleValue];
#else
    return [self floatValue];
#endif
}


@end

CGFLOAT_IS_DOUBLE is defined in CGBase.h conditionally by platform.

ipmcc
  • 29,581
  • 5
  • 84
  • 147
  • This is not even necessary, it's over-coding. If you call *[NSNumber numberWithDouble: value]* (for compiler versions that don't support literal numbers) you don't risk to lose any precision whether if the number is float or double. – Ramy Al Zuhouri Jun 12 '13 at 14:33
  • Yes, but you waste cycles to convert between float and double on platforms where CGFloat is a float. But whatever. Use this, don't use this. I wrote it a long time ago and I continue to use it. It works for me. – ipmcc Jun 12 '13 at 14:43
  • Thnaks @ipmcc, I'll use Lukas' solution but yours is what I was searching for originally. – Guillaume Algis Jun 12 '13 at 14:48
  • 2
    I find it odd this is not NSNumber already, since they did add methods for NSInteger. – Patrick Pijnappel Oct 18 '13 at 05:11