

 This page uses content from Wikipedia. The original article was at CUSIP. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)



A   CUSIP   is a nine-character alphanumeric code that identifies a North American financial security for the purposes of facilitating clearing and settlement of trades. The CUSIP was adopted as an American National Standard under Accredited Standards X9.6.



Task

Ensure the last digit   (i.e., the   check digit)   of the CUSIP code (the 1st column) is correct, against the following:

   037833100       Apple Incorporated 
   17275R102       Cisco Systems 
   38259P508       Google Incorporated 
   594918104       Microsoft Corporation 
   68389X106       Oracle Corporation   (incorrect)
   68389X105       Oracle Corporation 


Example pseudo-code below.
algorithm Cusip-Check-Digit(cusip) is
   Input: an 8-character CUSIP
 
   sum := 0
   for 1 ≤ i ≤ 8 do
      c := the ith character of cusip
      if c is a digit then
         v := numeric value of the digit c
      else if c is a letter then
         p := ordinal position of c in the alphabet (A=1, B=2...)
         v := p + 9
      else if c = "*" then
         v := 36
      else if c = "@" then
         v := 37
      else if' c = "#" then
         v := 38
      end if
      if i is even then
         v := v × 2
      end if
 
      sum := sum + int ( v div 10 ) + v mod 10
   repeat
 
   return (10 - (sum mod 10)) mod 10
end function
See related tasks
 
 SEDOL
 ISIN


(() => {
    'use strict';
 
    // cusipValid = Dict Char Int -> String -> Bool
    const cusipValid = charMap => s => {
        const
            ns = fromMaybe([])(
                traverse(flip(lookupDict)(charMap))(
                    chars(s)
                )
            );
        return 9 === ns.length && (
            last(ns) === rem(
                10 - rem(
                    sum(apList(
                        apList([quot, rem])(
                            zipWith(identity)(
                                cycle([identity, x => 2 * x])
                            )(take(8)(ns))
                        )
                    )([10]))
                )(10)
            )(10)
        );
    };
 
    //----------------------- TEST ------------------------
    // main :: IO ()
    const main = () => {
 
        // cusipMap :: Dict Char Int
        const cusipMap = dictFromList(
            zip(chars(
                "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#"
            ))(enumFrom(0)));
 
        console.log(unlines(map(
            apFn(
                s => validity => s + ' -> ' + str(validity)
            )(cusipValid(cusipMap))
        )([
            '037833100',
            '17275R102',
            '38259P508',
            '594918104',
            '68389X106',
            '68389X105'
        ])));
    };
 
 
    //----------------- GENERIC FUNCTIONS -----------------
 
    // Just :: a -> Maybe a
    const Just = x => ({
        type: 'Maybe',
        Nothing: false,
        Just: x
    });
 
 
    // Nothing :: Maybe a
    const Nothing = () => ({
        type: 'Maybe',
        Nothing: true,
    });
 
 
    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a =>
        b => ({
            type: 'Tuple',
            '0': a,
            '1': b,
            length: 2
        });
 
 
    // apFn :: (a -> b -> c) -> (a -> b) -> a -> c
    const apFn = f =>
        // Applicative instance for functions.
        // f(x) applied to g(x).
        g => x => f(x)(
            g(x)
        );
 
 
    // apList (<*>) :: [(a -> b)] -> [a] -> [b]
    const apList = fs =>
        // The sequential application of each of a list
        // of functions to each of a list of values.
        xs => fs.flatMap(
            f => xs.map(f)
        );
 
 
    // append (++) :: [a] -> [a] -> [a]
    // append (++) :: String -> String -> String
    const append = xs =>
        // A list or string composed by
        // the concatenation of two others.
        ys => xs.concat(ys);
 
 
    // chars :: String -> [Char]
    const chars = s =>
        s.split('');
 
 
    // cons :: a -> [a] -> [a]
    const cons = x =>
        xs => Array.isArray(xs) ? (
            [x].concat(xs)
        ) : 'GeneratorFunction' !== xs
        .constructor.constructor.name ? (
            x + xs
        ) : ( // cons(x)(Generator)
            function*() {
                yield x;
                let nxt = xs.next()
                while (!nxt.done) {
                    yield nxt.value;
                    nxt = xs.next();
                }
            }
        )();
 
 
    // cycle :: [a] -> Generator [a]
    function* cycle(xs) {
        const lng = xs.length;
        let i = 0;
        while (true) {
            yield(xs[i])
            i = (1 + i) % lng;
        }
    }
 
 
    // dictFromList :: [(k, v)] -> Dict
    const dictFromList = kvs =>
        Object.fromEntries(kvs);
 
 
    // enumFrom :: Enum a => a -> [a]
    function* enumFrom(x) {
        // A non-finite succession of enumerable
        // values, starting with the value x.
        let v = x;
        while (true) {
            yield v;
            v = succ(v);
        }
    }
 
 
    // flip :: (a -> b -> c) -> b -> a -> c
    const flip = f =>
        1 < f.length ? (
            (a, b) => f(b, a)
        ) : (x => y => f(y)(x));
 
 
    // fromEnum :: Enum a => a -> Int
    const fromEnum = x =>
        typeof x !== 'string' ? (
            x.constructor === Object ? (
                x.value
            ) : parseInt(Number(x))
        ) : x.codePointAt(0);
 
 
    // fromMaybe :: a -> Maybe a -> a
    const fromMaybe = def =>
        // A default value if mb is Nothing
        // or the contents of mb.
        mb => mb.Nothing ? def : mb.Just;
 
 
    // fst :: (a, b) -> a
    const fst = tpl =>
        // First member of a pair.
        tpl[0];
 
 
    // identity :: a -> a
    const identity = x =>
        // The identity function. (`id`, in Haskell)
        x;
 
 
    // last :: [a] -> a
    const last = xs =>
        // The last item of a list.
        0 < xs.length ? xs.slice(-1)[0] : undefined;
 
 
    // length :: [a] -> Int
    const length = xs =>
        // Returns Infinity over objects without finite
        // length. This enables zip and zipWith to choose
        // the shorter argument when one is non-finite,
        // like cycle, repeat etc
        (Array.isArray(xs) || 'string' === typeof xs) ? (
            xs.length
        ) : Infinity;
 
 
    // liftA2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
    const liftA2 = f => a => b =>
        a.Nothing ? a : b.Nothing ? b : Just(f(a.Just)(b.Just));
 
 
    // lookupDict :: a -> Dict -> Maybe b
    const lookupDict = k => dct => {
        const v = dct[k];
        return undefined !== v ? (
            Just(v)
        ) : Nothing();
    };
 
    // map :: (a -> b) -> [a] -> [b]
    const map = f =>
        // The list obtained by applying f
        // to each element of xs.
        // (The image of xs under f).
        xs => (
            Array.isArray(xs) ? (
                xs
            ) : xs.split('')
        ).map(f);
 
 
    // pureMay :: a -> Maybe a
    const pureMay = x => Just(x);
 
    // Given a type name string, returns a
    // specialised 'pure', where
    // 'pure' lifts a value into a particular functor.
 
    // pureT :: String -> f a -> (a -> f a)
    const pureT = t => x =>
        'List' !== t ? (
            'Either' === t ? (
                pureLR(x)
            ) : 'Maybe' === t ? (
                pureMay(x)
            ) : 'Node' === t ? (
                pureTree(x)
            ) : 'Tuple' === t ? (
                pureTuple(x)
            ) : pureList(x)
        ) : pureList(x);
 
 
    // pureTuple :: a -> (a, a)
    const pureTuple = x =>
        Tuple('')(x);
 
    // quot :: Int -> Int -> Int
    const quot = n =>
        m => Math.floor(n / m);
 
    // rem :: Int -> Int -> Int
    const rem = n => m => n % m;
 
    // snd :: (a, b) -> b
    const snd = tpl => tpl[1];
 
    // str :: a -> String
    const str = x =>
        x.toString();
 
    // succ :: Enum a => a -> a
    const succ = x => {
        const t = typeof x;
        return 'number' !== t ? (() => {
            const [i, mx] = [x, maxBound(x)].map(fromEnum);
            return i < mx ? (
                toEnum(x)(1 + i)
            ) : Error('succ :: enum out of range.')
        })() : x < Number.MAX_SAFE_INTEGER ? (
            1 + x
        ) : Error('succ :: Num out of range.')
    };
 
    // sum :: [Num] -> Num
    const sum = xs =>
        // The numeric sum of all values in xs.
        xs.reduce((a, x) => a + x, 0);
 
    // take :: Int -> [a] -> [a]
    // take :: Int -> String -> String
    const take = n =>
        // The first n elements of a list,
        // string of characters, or stream.
        xs => 'GeneratorFunction' !== xs
        .constructor.constructor.name ? (
            xs.slice(0, n)
        ) : [].concat.apply([], Array.from({
            length: n
        }, () => {
            const x = xs.next();
            return x.done ? [] : [x.value];
        }));
 
    // The first argument is a sample of the type
    // allowing the function to make the right mapping
 
    // toEnum :: a -> Int -> a
    const toEnum = e => x =>
        ({
            'number': Number,
            'string': String.fromCodePoint,
            'boolean': Boolean,
            'object': v => e.min + v
        } [typeof e])(x);
 
 
    // traverse :: (Applicative f) => (a -> f b) -> [a] -> f [b]
    const traverse = f =>
        // Collected results of mapping each element
        // of a structure to an action, and evaluating
        // these actions from left to right.
        xs => 0 < xs.length ? (() => {
            const
                vLast = f(xs.slice(-1)[0]),
                t = vLast.type || 'List';
            return xs.slice(0, -1).reduceRight(
                (ys, x) => liftA2(cons)(f(x))(ys),
                liftA2(cons)(vLast)(pureT(t)([]))
            );
        })() : [
            []
        ];
 
 
    // uncons :: [a] -> Maybe (a, [a])
    const uncons = xs => {
        // Just a tuple of the head of xs and its tail,
        // Or Nothing if xs is an empty list.
        const lng = length(xs);
        return (0 < lng) ? (
            Infinity > lng ? (
                Just(Tuple(xs[0])(xs.slice(1))) // Finite list
            ) : (() => {
                const nxt = take(1)(xs);
                return 0 < nxt.length ? (
                    Just(Tuple(nxt[0])(xs))
                ) : Nothing();
            })() // Lazy generator
        ) : Nothing();
    };
 
 
    // uncurry :: (a -> b -> c) -> ((a, b) -> c)
    const uncurry = f =>
        // A function over a pair, derived
        // from a curried function.
        x => ((...args) => {
            const
                xy = 1 < args.length ? (
                    args
                ) : args[0];
            return f(xy[0])(xy[1]);
        })(x);
 
 
    // unlines :: [String] -> String
    const unlines = xs =>
        // A single string formed by the intercalation
        // of a list of strings with the newline character.
        xs.join('\n');
 
 
    // zip :: [a] -> [b] -> [(a, b)]
    const zip = xs =>
        // Use of `take` and `length` here allows for zipping with non-finite
        // lists - i.e. generators like cycle, repeat, iterate.
        ys => {
            const
                lng = Math.min(length(xs), length(ys)),
                vs = take(lng)(ys);
            return take(lng)(xs).map(
                (x, i) => Tuple(x)(vs[i])
            );
        };
 
    // Use of `take` and `length` here allows zipping with non-finite lists
    // i.e. generators like cycle, repeat, iterate.
 
    // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    const zipWith = f => xs => ys => {
        const lng = Math.min(length(xs), length(ys));
        return Infinity > lng ? (() => {
            const
                as = take(lng)(xs),
                bs = take(lng)(ys);
            return Array.from({
                length: lng
            }, (_, i) => f(as[i])(
                bs[i]
            ));
        })() : zipWithGen(f)(xs)(ys);
    };
 
 
    // zipWithGen :: (a -> b -> c) ->
    // Gen [a] -> Gen [b] -> Gen [c]
    const zipWithGen = f => ga => gb => {
        function* go(ma, mb) {
            let
                a = ma,
                b = mb;
            while (!a.Nothing && !b.Nothing) {
                let
                    ta = a.Just,
                    tb = b.Just
                yield(f(fst(ta))(fst(tb)));
                a = uncons(snd(ta));
                b = uncons(snd(tb));
            }
        }
        return go(uncons(ga), uncons(gb));
    };
 
    // MAIN ---
    return main();
})();