Sachin
Sachin

Reputation: 765

Split a double by dot to two numbers

So I am trying to split a number in swift, I have tried searching for this on the internet but have had no success. So first I will start with a number like:

var number = 34.55

And from this number, I want to create two separate number by splitting from the dot. So the output should be something like:

var firstHalf = 34
var secondHalf = 55

Or the output can also be in an array of thats easier. How can I achieve this?

Upvotes: 7

Views: 4912

Answers (4)

Denis Zubkov
Denis Zubkov

Reputation: 137

Actually, it's not possible to split a double by dot into two INTEGER numbers. All earlier offered solutions will produce a bug in nearly 10% of cases.

Here's why:

The breaking case will be numbers with decimal parts starting with one or more zeroes, for example: 1.05, 11.00698, etc.

Any decimal part that starts with one or more zeroes will have those zeroes discarded when converted to integers. The result of those conversions:

1.05 will become (1, 5)

11.00698 will become (11, 698)

An ugly and hard to find bug is guaranteed...

The only way to meaningfully split a decimal number is to convert it to (Int, Double). Below is a simple extension to Double that does that:

extension Double {

    func splitAtDecimal() -> (Int, Double) {

        let whole = Int(self)
        let decimal = self - Darwin.floor(self)

        return (whole, decimal)
    }
}

Upvotes: 2

George Filippakos
George Filippakos

Reputation: 16569

Add the following extension:

extension Double {

func splitIntoParts(decimalPlaces: Int, round: Bool) -> (leftPart: Int, rightPart: Int) {

    var number = self
    if round {
        //round to specified number of decimal places:
        let divisor = pow(10.0, Double(decimalPlaces))
        number = Darwin.round(self * divisor) / divisor
    }

    //convert to string and split on decimal point:
    let parts = String(number).components(separatedBy: ".")

    //extract left and right parts:
    let leftPart = Int(parts[0]) ?? 0
    let rightPart = Int(parts[1]) ?? 0

    return(leftPart, rightPart)

}

Usage - Unrounded:

let number:Double = 95.99999999
let parts = number.splitIntoParts(decimalPlaces: 3, round: false)

print("LeftPart: \(parts.leftPart) RightPart: \(parts.rightPart)")

Outputs:

LeftPart: 95 RightPart: 999

Usage Rounded:

let number:Double = 95.199999999
let parts = number.splitIntoParts(decimalPlaces: 1, round: true)

Outputs:

LeftPart: 95 RightPart: 2

Upvotes: 2

royhowie
royhowie

Reputation: 11171

The easiest way would be to first cast the double to a string:

var d = 34.55
var b = "\(d)" // or String(d)

then split the string with the global split function:

var c = split(b) { $0 == "." }   // [34, 55]

You can also bake this functionality into a double:

extension Double {
    func splitAtDecimal() -> [Int] {
        return (split("\(self)") { $0 == "." }).map({
            return String($0).toInt()!
        })
    }
}

This would allow you to do the following:

var number = 34.55
print(number.splitAtDecimal())   // [34, 55]

Upvotes: 6

Tom van der Woerdt
Tom van der Woerdt

Reputation: 29985

Well, what you have there is a float, not a string. You can't really "split" it, and remember that a float is not strictly limited to 2 digits after the separator.

One solution is :

var firstHalf = Int(number)
var secondHalf = Int((number - firstHalf) * 100)

It's nasty but it'll do the right thing for your example (it will, however, fail when dealing with numbers that have more than two decimals of precision)

Alternatively, you could convert it into a string and then split that.

var stringified = NSString(format: "%.2f", number)
var parts = stringifed.componentsSeparatedByString(".")

Note that I'm explicitly calling the formatter here, to avoid unwanted behavior of standard float to string conversions.

Upvotes: 3

Related Questions