Testing if a Decimal is a whole number in Swift
Thanks for the comments! Here is what I am using now.
extension Decimal {
var isWholeNumber: Bool {
return self.isZero || (self.isNormal && self.exponent >= 0)
}
}
Checking if a double value is an integer - Swift
Try 'flooring' the double value then checking if it is unchanged:
let dbl = 2.0
let isInteger = floor(dbl) == dbl // true
Fails if it is not an integer
let dbl = 2.4
let isInteger = floor(dbl) == dbl // false
Check if number is decimal with swift
If you round the number down (which you can do by using the floor function), and then subtract it from the original number, you will get the difference between the two.
if (number - floor(number) > 0.000001) { // 0.000001 can be changed depending on the level of precision you need
// decimal
}
Edit --
My original answer recommended calculating the difference between the number and its floored equivalent to see if there were any units after the decimal points. However, as later described, there may be a rounding error which causes the representation of a value in memory to be slightly different than what it's actually meant to be.
For example, 3.0 could be represented as 3.00000000000001, and therefore the number - floor(number) > 0
would return true, even though it should've theoretically returned false as the offset would be 0.00000000000001.
Therefore please use @jessy's answer below.
Check if NSDecimalNumber is whole number
@interface NSDecimalNumber (IsIntegerNumber)
@property (readonly) BOOL isIntegerNumber;
@end
@implementation NSDecimalNumber (IsIntegerNumber)
-(BOOL)isIntegerNumber {
NSDecimalValue value = [self decimalValue];
if (NSDecimalIsNotANumber(&value)) return NO;
NSDecimal rounded;
NSDecimalRound(&rounded, &value, 0, NSRoundPlain);
return NSDecimalCompare(&rounded, &value) == NSOrderedSame;
}
@end
Display Double as Int if it is a whole number in Swift
Convert Double into Number and then to String if u want to show it on label
let i = 1.0
let j = 1.2345
// Value in String
let a = NSNumber(value: j).stringValue // "1.2345"
let b = NSNumber(value: i).stringValue // "1"
// Value in Double
let c = NSNumber(value: i).doubleValue // 1.0
let d = NSNumber(value: j).doubleValue // 1.2345
Swift Formatting String to have 2 decimal numbers if it is not a whole number
You can extend FloatingPoint
to check if it is a whole number and use a condition to set the minimumFractionDigits
property of the NumberFormatter
to 0 in case it is true otherwise set it to 2:
extension Formatter {
static let custom: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
return formatter
}()
}
extension FloatingPoint {
var isWholeNumber: Bool { isNormal ? self == rounded() : isZero }
var custom: String {
Formatter.custom.minimumFractionDigits = isWholeNumber ? 0 : 2
return Formatter.custom.string(for: self) ?? ""
}
}
Playground testing:
1.0.custom // "1"
1.5.custom // "1.50"
1.75.custom // "1.75"
Getting the decimal part of a double in Swift
Without converting it to a string, you can round up to a number of decimal places like this:
let x:Double = 1234.5678
let numberOfPlaces:Double = 4.0
let powerOfTen:Double = pow(10.0, numberOfPlaces)
let targetedDecimalPlaces:Double = round((x % 1.0) * powerOfTen) / powerOfTen
Your output would be
0.5678
Count number of decimal places in a Float (or Decimal) in Swift
Doing this with Decimal is fairly straightforward, provided you correctly create your Decimal. Decimals are stored as significand * 10^exponent
. significand
is normalized to the smallest integer possible. So for 1230, the significand is 123 and the exponent is 1. For 1.23 the significand is also 123 and the exponent is -2. That leads us to:
extension Decimal {
var significantFractionalDecimalDigits: Int {
return max(-exponent, 0)
}
}
However, you must be very careful constructing your Decimal. If you construct it from a Double, you will already have applied binary rounding errors. So for example:
let n = Decimal(0.111) // 0.11100000000000002048 because you passed a Double
n.significantFractionalDecimalDigits // 20
vs.
let n = Decimal(string: "0.111")!
n.significantFractionalDecimalDigits // 3 what you meant
Keep in mind of course that Decimal has a maximum number of significant digits, so it may still apply rounding.
let n = Decimal(string: "12345678901235678901234567890.1234567890123456789")!
n.significantFractionalDecimalDigits // 9 ("should" be 19)
And if you're walking down this road at all, you really must read the Floating Point Guide and the canonical StackOverflow question: Is floating point math broken?
Related Topics
Realm Swift: Always Put Nil Values Last in Sort
Swift 4.2 - _Shared Attribute Near Type
Obtain Nsurl from Uiimagepickercontroller
How to Masking the Last Number in Swift
Way to Purge All But One Object Types (Models) in a Realm
How Marquee Text of Label on Swift
Swift Radio Streaming Avplayer
I Can't Include ' Symbol to Regular Expressions
Swift. Combine. How to Call a Publisher Block More Than Once When Retry
How to Create a Circle with Rounded Ends for Each Quadrant
How to Save a Custom Class as an Attribute of a Coredata Entity in Swift 3
Cast to Different C Struct Unsafe Pointer in Swift
Swift For-In Loop with Enumerate on Custom Array2D Class