Skip to content

Robust Integer Divide

Chris Zheng edited this page Aug 12, 2013 · 4 revisions

Here is an example of a program that uses retries to compute some nasty inputs in an array:

So the code manages to deal with keywords and strings to still give a 'reasonable' output without falling over

(int-div-pairs [[12 8] [:90 "9"] [:10 "nil"] [nil :100] [:hello :hello]])
=> [1 10 :infinity 0 :infinity]

Here is the code:

(ns ribol.integer-divide
  (:require [ribol.core :refer :all]
            [midje.sweet :refer :all]))

(defn int-div [n m]
  (prn n 'divide-by m)
  (anticipate
   [ArithmeticException
    (do (println  "- div-error - \n")
        (raise [:div-error {:numer n :denom m}]))
    #{ClassCastException NullPointerException}
    (do (println  "- input-error - \n")
        (raise [:input-error {:numer n :denom m}]))]
   (let [q   (quot n m)
         diff (- n (* q m))]
     (if (zero? diff)
       (do (println  "- CORRECT! - \n")
           q)
       (do (println  "- not-exact - \n")
           (raise [:not-exact {:numer n :denom m :diff diff}]))))))

(defn int-div-pairs [arr]
  (manage
   (mapv #(apply int-div %) arr)
   (on :input-error [numer denom]
       (cond (keyword? numer)
             (continue (int-div (name numer) denom))
             (keyword? denom)
             (continue (int-div numer (name denom)))
             (string? numer)
             (continue
              (int-div (anticipate [NumberFormatException 0]
                                   (Integer/parseInt numer)) denom))
             (string? denom)
             (continue
              (int-div numer (anticipate [NumberFormatException 0]
                                         (Integer/parseInt denom))))
             (nil? denom)
             (continue (int-div numer 0))
             (nil? numer)
             (continue (int-div 0 denom))))
   (on :div-error [numer denom]
       (cond (= 0 denom)
             (do (println "- USING INFINITY -\n")
               (continue :infinity))
             :else :failed))
   (on :not-exact [numer denom diff]
       (continue (int-div (- numer diff) denom)))))

Here is the printed output. Note that the program retries its inputs with continue until it gets a result. It is not the most pretty program but it is robust to a lot of inputs:

12 divide-by 8
- not-exact - 

8 divide-by 8
- CORRECT! - 

:90 divide-by :9
- input-error - 

"90" divide-by :9
- input-error - 

"90" divide-by "9"
- input-error - 

90 divide-by "9"
- input-error - 

90 divide-by 9
- CORRECT! - 

:10 divide-by nil
- input-error - 

"10" divide-by nil
- input-error - 

10 divide-by nil
- input-error - 

10 divide-by 0
- div-error - 

- USING INFINITY -

nil divide-by :100
- input-error - 

nil divide-by "100"
- input-error - 

nil divide-by 100
- input-error - 

0 divide-by 100
- CORRECT! - 

:hello divide-by :hello
- input-error - 

"hello" divide-by :hello
- input-error - 

"hello" divide-by "hello"
- input-error - 

0 divide-by "hello"
- input-error - 

0 divide-by 0
- div-error - 

- USING INFINITY -
Clone this wiki locally