NEW: Learn to build the incredible iOS 15 Weather app today! >>

SOLVED: Best practices concerning floating-point division?

Forums > Swift

I'm just now being bitten by a divide-by-zero bug in my code that silently returns inf instead of crashing--a surprise to me, but ok, I'll do whatever Swifty thing people do to catch divide-by-zero issues in their code. But what is the Swifty thing? I thought it would be a compile setting in Xcode, but I don't see anything, and the closest thing to a sensible answer I've found is to explicitly check for zero in the denominator, or perhaps to do the operation and check for .isInfinite in the result. What's the best practice for this?

   

When I first read about Swift's guard statement, I thought it was brilliant. I imagined Beefeater guards standing outside the Towers of London in their impratical scarlet and gold uniforms with their pikes challenging anyone trying to get in.

If you knew the password, or had the right credentials, you were free to enter and go where you wanted. If not, you weren't even allowed inside. End of story.

Your question seems to dance around a solution requiring very precise maths, perhaps using advanced libraries. Maybe the solution to divide-by-zero is found there. I can't begin to help, as I have never looked into those types of libraries.

But when I first read your question, I thought how I would structure my function calls with a series of guard statements. Don't even try to calculate the formula unless all the parameters are first vetted by the Beefeaters!

Good luck. Please let us know what your strategy is and how you solved this.

1      

It really depend on what you are doing at that point in your code, however I would not let it run silently without catching it as it may effect another part of your code which may crash there and you could spend sometime looking for it.

As @Obelix suggested you could use a guard to it to bail out (in Paul's words) with a default value (I used 1 in example)

func divide(first: Int, second: Int) -> Int {
    guard second != 0 else { return 1 }

    return first / second
}

let answer = divide(first: 12, second: 0)
print(answer)

or you can also use if

var first = 12
var second = 0
var answer : Int

if second != 0 {
    answer = first / second
} else {
    answer = 1
}

print(answer)

Hope that is clear

1      

@nigel advises:

func divide(first: Int, second: Int) -> Int {  // maybe return OPTIONAL Int?
    guard second != 0 else { return 1 }  // maybe return nil, instead of 1 ?
    return first / second  //  What if second ISN'T zero, but nearly zero?
}

let answer = divide(first: 12, second: 0)
print(answer)

I agree with this approach. However, @sagan noted he was getting .isInfinite as a result?

So for some values of second, in your example, the guard might not fail because the value isn't exactly zero. But it's so microscopically small that it may as well be zero. And the returned result is nearly infinite?

Is this how I am understanding @sagan's problem?

In anycase, I'm out of ideas. It seems this type of impossibly small number might be something a maths library might address better?

1      

Thanks everyone! I guess the ultimate answer is that there's not a consensus "best practice" for this sort of thing. So I just went ad-hoc: do the division and check the answer for .isInfinite then decide what to do from there. I don't know if it counts as advanced math. I'm telling one thing to rotate a certain amount based on the amount that another thing rotated and a scale value, which can legitimately be zero. In case anyone's interested, the app (github repo) --it's a toy, hopefully a fun toy-- runs on both macOS and iOS (I would never have believed I would write an app that would do both). Cheers

   

I concur that checking the answer for .isInfinite is the best solution. Floating point division really is subtraction of the two numbers' exponents. Whether the difference between the two exponents is large enough for an overflow result depends on both exponents, not merely the exponent of the number close to zero.

1      

hi,

one side-note: you can get .isNan as a result, rather than isInfinite (e.g., computing 0/0)

hope that helps,

DMG

1      

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS, you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Learn More

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.