Need help with exercism Armstrong exercise

Hi,

I’m working on the armstrong exercise on exercism, Armstrong Numbers in Clojure on Exercism but I’m failing the 10th and 11th tests. I’m assuming it’s something around how I’m handling larger numbers, but I’m not sure.

The following is my code, and it fails for the two numbers, 115132219018763992565095597973971522401 and 186709961001538790100634132976990. Any pointers are appreciated

(ns armstrong-numbers)
(require '[clojure.math :as math])

(defn- digits
"Returns the digits of the number as a sequence"
[num]
(map #(read-string (str %)) (str num)))

(defn- sum-of-armstrong-powers
[digi]
(reduce + (map #(bigint (math/pow % (count digi))) digi)))

(defn armstrong?
"Returns true if the given number is an Armstrong number;
otherwise, it returns false."
[num]
(= num (sum-of-armstrong-powers (digits num))))
1 Like

The issue seems to be that math/pow returns a floating point number (a double). With smaller numbers that’s not a problem, but at a certain point you start to get rounding, since a double has a fixed number of bits available. You convert it to a bigint, but at that point the damage has been done.

A solution is to write your own power function that uses integers throughout. *' will automatically convert to bigint if the number gets too big.

(ns armstrong-numbers
  (:require [clojure.math :as math]))

(defn- digits
  "Returns the digits of the number as a sequence"
  [num]
  (map #(read-string (str %)) (str num)))

(defn pow-int [n exp]
  (loop [res 1
         exp exp]
    (if (= 0 exp)
      res
      (recur (*' res n) (dec exp)))))

(defn- sum-of-armstrong-powers
  [digi]
  (let [len (count digi)]
    (reduce + (map #(pow-int % len) digi))))

(defn armstrong?
  "Returns true if the given number is an Armstrong number;
  otherwise, it returns false."
  [num]
  (= num (sum-of-armstrong-powers (digits num))))

(armstrong? 115132219018763992565095597973971522401)
;; => true
(armstrong? 186709961001538790100634132976990)
;; => true

Welcome to ClojureVerse! <3

1 Like

An alternative pow-int impl, where BigInteger comes from (:import (java.math BigInteger)):

(defn pow-int [n exp]
  (.pow (BigInteger/valueOf n) exp))

Hi,

I’m working on the armstrong exercise on exercism, Armstrong Numbers in Clojure on Exercism but I’m failing the 10th and 11th tests. I’m assuming it’s something around how I’m handling larger numbers, but I’m not sure.

The following is my code, and it fails for the two numbers, 115132219018763992565095597973971522401 and 186709961001538790100634132976990. Any pointers are appreciated

(ns armstrong-numbers)
(require '[clojure.math :as math])

(defn- digits
"Returns the digits of the number as a sequence"
[num]
(map #(read-string (str %)) (str num)))

(defn- sum-of-armstrong-powers
[digi]
(reduce + (map #(bigint (math/pow % (count digi))) digi)))

(defn armstrong?
"Returns true if the given number is an Armstrong number;
otherwise, it returns false."
[num]
(= num (sum-of-armstrong-powers (digits num))))

Thanks for the pointers, I assumed it would need to be something along those lines. I notice you also assign the length, does it recalculate it each time if I leave it in the map or is it just cleaner to have it outside as an assignment?