CUSIP: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Excel LAMBDA}}: Added a draft using the LAMBDA() function which is defined in recent Excel beta builds.)
 
(36 intermediate revisions by 23 users not shown)
Line 17: Line 17:


;Example pseudo-code below.
;Example pseudo-code below.
<lang>algorithm Cusip-Check-Digit(cusip) is
<syntaxhighlight lang=text>algorithm Cusip-Check-Digit(cusip) is
Input: an 8-character CUSIP
Input: an 8-character CUSIP


Line 43: Line 43:
return (10 - (sum mod 10)) mod 10
return (10 - (sum mod 10)) mod 10
end function</lang>
end function</syntaxhighlight>


;See related tasks:
;See related tasks:
Line 49: Line 49:
* [[Validate_International_Securities_Identification_Number|ISIN]]
* [[Validate_International_Securities_Identification_Number|ISIN]]
<br>
<br>

=={{header|11l}}==
{{trans|Python}}

<syntaxhighlight lang=11l>F cusip_check(=cusip)
I cusip.len != 9
X.throw ValueError(‘CUSIP must be 9 characters’)

cusip = cusip.uppercase()
V total = 0
L(i) 8
V v = 0
V c = cusip[i]
I c.is_digit()
v = Int(c)
E I c.is_alpha()
V p = c.code - ‘A’.code + 1
v = p + 9
E I c == ‘*’
v = 36
E I c == ‘@’
v = 37
E I c == ‘#’
v = 38

I i % 2 != 0
v *= 2

total += v I/ 10 + v % 10
V check = (10 - (total % 10)) % 10
R String(check) == cusip.last

V codes = [‘037833100’,
‘17275R102’,
‘38259P508’,
‘594918104’,
‘68389X106’,
‘68389X105’]
L(code) codes
print(code‘: ’(I cusip_check(code) {‘valid’} E ‘invalid’))</syntaxhighlight>

{{out}}
<pre>
037833100: valid
17275R102: valid
38259P508: valid
594918104: valid
68389X106: invalid
68389X105: valid
</pre>


=={{header|360 Assembly}}==
=={{header|360 Assembly}}==
<lang 360asm>* CUSIP 07/06/2018
<syntaxhighlight lang=360asm>* CUSIP 07/06/2018
CUSIP CSECT
CUSIP CSECT
USING CUSIP,R13 base register
USING CUSIP,R13 base register
Line 131: Line 181:
PG DC CL80'CUSIP ......... is... valid'
PG DC CL80'CUSIP ......... is... valid'
YREGS
YREGS
END CUSIP</lang>
END CUSIP</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 140: Line 190:
CUSIP 68389X106 isn't valid
CUSIP 68389X106 isn't valid
CUSIP 68389X105 is valid
CUSIP 68389X105 is valid
</pre>

=={{header|Action!}}==
{{libheader|Action! Tool Kit}}
<syntaxhighlight lang=Action!>INCLUDE "D2:CHARTEST.ACT" ;from the Action! Tool Kit

BYTE FUNC Verify(CHAR ARRAY code)
BYTE i,c,v
CARD sum

IF code(0)#9 THEN
RETURN (0)
ELSEIF IsDigit(code(1))=0 THEN
RETURN (0)
FI

sum=0
FOR i=2 TO code(0)
DO
c=code(i)
IF IsDigit(c) THEN
v=c-'0
ELSEIF IsAlpha(c) THEN
v=ToUpper(c)-'A+10
ELSEIF c='* THEN
v=36
ELSEIF c='@ THEN
v=37
ELSEIF c='# THEN
v=38
ELSE
RETURN (0)
FI

IF (i&1)=0 THEN
v==*2
FI

sum==+v/10+v MOD 10
OD

v=(10-(sum MOD 10)) MOD 10
IF v#code(1)-'0 THEN
RETURN (0)
FI
RETURN (1)

PROC Test(CHAR ARRAY code)
Print(code)
IF Verify(code) THEN
PrintE(" is valid")
ELSE
PrintE(" is invalid")
FI
RETURN

PROC Main()
Put(125) PutE() ;clear the screen
Test("037833100")
Test("17275R102")
Test("38259P508")
Test("594918104")
Test("68389X106")
Test("68389X105")
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/CUSIP.png Screenshot from Atari 8-bit computer]
<pre>
037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
68389X105 is valid
</pre>
</pre>


=={{header|Ada}}==
=={{header|Ada}}==
<lang Ada>with Ada.Text_IO;
<syntaxhighlight lang=Ada>with Ada.Text_IO;


procedure Cusip_Test is
procedure Cusip_Test is
Line 196: Line 320:
end if;
end if;
end loop;
end loop;
end Cusip_Test;</lang>
end Cusip_Test;</syntaxhighlight>
{{Out}}
{{Out}}
<pre>037833100: valid
<pre>037833100: valid
Line 207: Line 331:


=={{header|ALGOL 68}}==
=={{header|ALGOL 68}}==
<lang algol68>BEGIN
<syntaxhighlight lang=algol68>BEGIN
# returns TRUE if cusip is a valid CUSIP code #
# returns TRUE if cusip is a valid CUSIP code #
OP ISCUSIP = ( STRING cusip )BOOL:
OP ISCUSIP = ( STRING cusip )BOOL:
Line 255: Line 379:
test cusip( "68389X106" );
test cusip( "68389X106" );
test cusip( "68389X105" )
test cusip( "68389X105" )
END</lang>
END</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 268: Line 392:
=={{header|ALGOL W}}==
=={{header|ALGOL W}}==
Based on Algol 68
Based on Algol 68
<lang algolw>begin % returns true if cusip is a valid CUSIP code %
<syntaxhighlight lang=algolw>begin % returns true if cusip is a valid CUSIP code %
logical procedure isCusip ( string(9) value cusip ) ;
logical procedure isCusip ( string(9) value cusip ) ;
begin
begin
Line 302: Line 426:
testCusip( "68389X105" )
testCusip( "68389X105" )
end testCases
end testCases
end.</lang>
end.</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 314: Line 438:


=={{header|AppleScript}}==
=={{header|AppleScript}}==
<lang applescript>use AppleScript version "2.4"
<syntaxhighlight lang=applescript>use AppleScript version "2.4"
use framework "Foundation"
use framework "Foundation"
use scripting additions
use scripting additions
Line 593: Line 717:
return lst
return lst
end tell
end tell
end zipWith</lang>
end zipWith</syntaxhighlight>
{{Out}}
{{Out}}
<pre>037833100 -> true
<pre>037833100 -> true
Line 601: Line 725:
68389X106 -> false
68389X106 -> false
68389X105 -> true</pre>
68389X105 -> true</pre>

=={{header|Arturo}}==
{{trans|Ruby}}
<syntaxhighlight lang=rebol>validCUSIP?: function [cusip][
s: 0
alpha: `A`..`Z`

loop.with:'i chop cusip 'c [
v: 0

case ø
when? [numeric? c] -> v: to :integer to :string c
when? [in? c alpha] -> v: (index alpha c) + 1 + 9
when? [c = `*`] -> v: 36
when? [c = `@`] -> v: 37
when? [c = `#`] -> v: 38
else []

if odd? i -> v: 2 * v

s: s + (v / 10) + (v % 10)
]
check: (10 - (s % 10)) % 10

return check = to :integer to :string last cusip
]

loop ["037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105"] 'cusip [
print [cusip "=>" (validCUSIP? cusip)? -> "VALID" -> "INVALID"]
]</syntaxhighlight>

{{out}}

<pre>037833100 => VALID
17275R102 => VALID
38259P508 => VALID
594918104 => VALID
68389X106 => INVALID
68389X105 => VALID</pre>


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==
<lang AutoHotkey>Cusip_Check_Digit(cusip){
<syntaxhighlight lang=AutoHotkey>Cusip_Check_Digit(cusip){
sum := 0, i := 1, x := StrSplit(cusip)
sum := 0, i := 1, x := StrSplit(cusip)
while (i <= 8) {
while (i <= 8) {
Line 623: Line 786:
}
}
return (Mod(10 - Mod(sum, 10), 10) = x[9])
return (Mod(10 - Mod(sum, 10), 10) = x[9])
}</lang>
}</syntaxhighlight>
Examples:<lang AutoHotkey>data =
Examples:<syntaxhighlight lang=AutoHotkey>data =
(
(
037833100
037833100
Line 637: Line 800:
loop, Parse, data, `n, `r
loop, Parse, data, `n, `r
output .= A_LoopField "`t" Cusip_Check_Digit(A_LoopField) "`n"
output .= A_LoopField "`t" Cusip_Check_Digit(A_LoopField) "`n"
MsgBox % output</lang>
MsgBox % output</syntaxhighlight>
{{out}}
{{out}}
<pre>Cusip Valid
<pre>Cusip Valid
Line 648: Line 811:


=={{header|AWK}}==
=={{header|AWK}}==
<lang AWK>
<syntaxhighlight lang=AWK>
# syntax: GAWK -f CUSIP.AWK
# syntax: GAWK -f CUSIP.AWK
BEGIN {
BEGIN {
Line 690: Line 853:
return(substr(n,9,1) == x ? 1 : 0)
return(substr(n,9,1) == x ? 1 : 0)
}
}
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 700: Line 863:
68389X105 1
68389X105 1
</pre>
</pre>

=={{header|BASIC}}==
==={{header|FreeBASIC}}===
<syntaxhighlight lang=freebasic>' version 04-04-2017
' compile with: fbc -s console

sub cusip(input_str As String)

Print input_str;
If Len(input_str) <> 9 Then
Print " length is incorrect, invalid cusip"
Return
End If

Dim As Long i, v , sum
Dim As UByte x

For i = 1 To 8
x = input_str[i-1]
Select Case x
Case Asc("0") To Asc("9")
v = x - Asc("0")
Case Asc("A") To Asc("Z")
v = x - Asc("A") + 1 + 9
Case Asc("*")
v= 36
Case Asc("@")
v = 37
Case Asc("#")
v = 38
Case Else
Print " found a invalid character, invalid cusip"
return
End Select

If (i And 1) = 0 Then v = v * 2
sum = sum + v \ 10 + v Mod 10
Next

sum = (10 - (sum Mod 10)) Mod 10
If sum = (input_str[8] - Asc("0")) Then
Print " is valid"
Else
Print " is invalid"
End If

End Sub

' ------=< MAIN >=------

Data "037833100", "17275R102", "38259P508"
Data "594918104", "68389X106", "68389X105"

Dim As String input_str

Print
For i As Integer = 1 To 6
Read input_str
cusip(input_str)
Next

' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End</syntaxhighlight>
{{out}}
<pre>037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
68389X105 is valid</pre>

==={{header|VBA}}===
<syntaxhighlight lang=vb>Private Function Cusip_Check_Digit(s As Variant) As Integer
Dim Sum As Integer, c As String, v As Integer
For i = 1 To 8
c = Mid(s, i, 1)
If IsNumeric(c) Then
v = Val(c)
Else
Select Case c
Case "a" To "z"
v = Asc(c) - Asc("a") + 10
Case "A" To "Z"
v = Asc(c) - Asc("A") + 10
Case "*"
v = 36
Case "@"
v = 37
Case "#"
v = 38
Case Else
Debug.Print "not expected"
End Select
End If
If i Mod 2 = 0 Then v = v * 2
Sum = Sum + Int(v \ 10) + v Mod 10
Next i
Cusip_Check_Digit = (10 - (Sum Mod 10)) Mod 10
End Function</syntaxhighlight>{{out}}
<pre>037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 not valid
68389X105 is valid</pre>

==={{header|Visual Basic .NET}}===
{{trans|C#}}
<syntaxhighlight lang=vbnet>Module Module1

Function IsCUSIP(s As String) As Boolean
If s.Length <> 9 Then
Return False
End If

Dim sum = 0
For i = 0 To 7
Dim c = s(i)

Dim v As Integer
If "0" <= c AndAlso c <= "9" Then
v = Asc(c) - 48
ElseIf "A" <= c AndAlso c <= "Z" Then
v = Asc(c) - 55 ' Lower case letters are apparently invalid
ElseIf c = "*" Then
v = 36
ElseIf c = "#" Then
v = 38
Else
Return False
End If

If i Mod 2 = 1 Then
v *= 2 ' check if odd as using 0-based indexing
End If
sum += v \ 10 + v Mod 10
Next
Return Asc(s(8)) - 48 = (10 - (sum Mod 10)) Mod 10
End Function

Sub Main()
Dim candidates As New List(Of String) From {
"037833100",
"17275R102",
"38259P508",
"594918104",
"68389X106",
"68389X105"
}

For Each candidate In candidates
Console.WriteLine("{0} -> {1}", candidate, If(IsCUSIP(candidate), "correct", "incorrect"))
Next
End Sub

End Module</syntaxhighlight>
{{out}}
<pre>037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct</pre>

==={{header|Yabasic}}===
{{trans|FreeBASIC}}
<syntaxhighlight lang=Yabasic>sub cusip(inputStr$)
local i, v, sum, x$
Print inputStr$;
If Len(inputStr$) <> 9 Print " length is incorrect, invalid cusip" : return
For i = 1 To 8
x$ = mid$(inputStr$, i, 1)
switch x$
Case "*": v = 36 : break
Case "@": v = 37 : break
Case "#": v = 38 : break
default:
if x$ >= "A" and x$ <= "Z" then
v = asc(x$) - Asc("A") + 10
elsif x$ >= "0" and x$ <= "9" then
v = asc(x$) - asc("0")
else
Print " found a invalid character, invalid cusip"
return
end if
End switch
If and(i, 1) = 0 v = v * 2
sum = sum + int(v / 10) + mod(v, 10)
Next
sum = mod(10 - mod(sum, 10), 10)
If sum = asc(mid$(inputStr$, 9, 1)) - Asc("0") Then
Print " is valid"
Else
Print " is invalid"
End If
End Sub
// ------=< MAIN >=------
Data "037833100", "17275R102", "38259P508"
Data "594918104", "68389X106", "68389X105", ""
Print
do
Read inputStr$
if inputStr$ = "" break
cusip(inputStr$)
loop
</syntaxhighlight>

=={{header|BCPL}}==
<syntaxhighlight lang=bcpl>get "libhdr"

let validcusip(c) = valof
$( let sum = 0
unless c%0 = 9 resultis false
for i = 1 to 8 do
$( let v = ( 2 - (i & 1) ) * valof
$( test '0' <= c%i <= '9'
then resultis c%i - '0'
or test 'A' <= c%i <= 'Z'
then resultis 10 + c%i - 'A'
or test c%i = '**'
then resultis 36
or test c%i = '@'
then resultis 37
or test c%i = '#'
then resultis 38
else resultis -1
$)
sum := sum + v/10 + v rem 10
$)
resultis (10 - (sum rem 10)) rem 10 = c%9 - '0'
$)

let show(c) be
writef("%S: %Svalid*N", c, validcusip(c) -> "", "in")
let start() be
$( show("037833100")
show("17275R102")
show("38259P508")
show("594918104")
show("68389X106")
show("68389X105")
$)</syntaxhighlight>
{{out}}
<pre>037833100: valid
17275R102: valid
38259P508: valid
594918104: valid
68389X106: invalid
68389X105: valid</pre>


=={{header|C}}==
=={{header|C}}==
Reads CUSIP strings from a file and prints results to console, usage printed on incorrect invocation.
Reads CUSIP strings from a file and prints results to console, usage printed on incorrect invocation.
<syntaxhighlight lang=C>
<lang C>
#include<stdlib.h>
#include<stdlib.h>
#include<stdio.h>
#include<stdio.h>
Line 757: Line 1,181:
return 0;
return 0;
}
}
</syntaxhighlight>
</lang>
Input file :
Input file :
<pre>
<pre>
Line 783: Line 1,207:
=={{header|C sharp|C#}}==
=={{header|C sharp|C#}}==
{{trans|Java}}
{{trans|Java}}
<lang csharp>using System;
<syntaxhighlight lang=csharp>using System;
using System.Collections.Generic;
using System.Collections.Generic;


Line 799: Line 1,223:
}
}
else if (c >= 'A' && c <= 'Z') {
else if (c >= 'A' && c <= 'Z') {
v = c - 64; // lower case letters apparently invalid
v = c - 55; // lower case letters apparently invalid
}
}
else if (c == '*') {
else if (c == '*') {
Line 830: Line 1,254:
}
}
}
}
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>037833100 -> correct
<pre>037833100 -> correct
Line 841: Line 1,265:
=={{header|C++}}==
=={{header|C++}}==
{{trans|C#}}
{{trans|C#}}
<lang cpp>#include <iostream>
<syntaxhighlight lang=cpp>#include <iostream>
#include <vector>
#include <vector>


Line 855: Line 1,279:
v = c - '0';
v = c - '0';
} else if ('A' <= c && c <= 'Z') {
} else if ('A' <= c && c <= 'Z') {
v = c - '@';
v = c - 'A' + 10;
} else if (c = '*') {
} else if (c = '*') {
v = 36;
v = 36;
} else if (c = '@') {
v = 37;
} else if (c = '#') {
} else if (c = '#') {
v = 38;
v = 38;
Line 889: Line 1,315:


return 0;
return 0;
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>037833100 -> correct
<pre>037833100 -> correct
Line 900: Line 1,326:
=={{header|Caché ObjectScript}}==
=={{header|Caché ObjectScript}}==


<lang cos>Class Utils.Check [ Abstract ]
<syntaxhighlight lang=cos>Class Utils.Check [ Abstract ]
{
{


Line 918: Line 1,344:
}
}


}</lang>
}</syntaxhighlight>
{{out|Examples}}
{{out|Examples}}
<pre>USER>For { Read s Quit:s="" Write ": "_##class(Utils.Check).CUSIP(s), ! }
<pre>USER>For { Read s Quit:s="" Write ": "_##class(Utils.Check).CUSIP(s), ! }
Line 931: Line 1,357:


=={{header|Clojure}}==
=={{header|Clojure}}==
<lang Clojure>
<syntaxhighlight lang=Clojure>
(defn- char->value
(defn- char->value
"convert the given char c to a value used to calculate the cusip check sum"
"convert the given char c to a value used to calculate the cusip check sum"
Line 938: Line 1,364:
(cond
(cond
(and (>= int-char (int \0)) (<= int-char (int \9))) (- int-char 48)
(and (>= int-char (int \0)) (<= int-char (int \9))) (- int-char 48)
(and (>= int-char (int \A)) (<= int-char (int \Z))) (- int-char 64)
(and (>= int-char (int \A)) (<= int-char (int \Z))) (- int-char 55)
(= c \*) 36
(= c \*) 36
(= c \@) 37
(= c \@) 37
Line 975: Line 1,401:
"show some nice output for the Rosetta Wiki"
"show some nice output for the Rosetta Wiki"
[]
[]
(doseq [cusip ["037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105"
(doseq [cusip ["037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105" "EXTRACRD8"
"EXTRACRD8" "BADCUSIP!" "683&9X106" "68389x105" "683$9X106" "68389}105"]]
"EXTRACRD9" "BADCUSIP!" "683&9X106" "68389x105" "683$9X106" "68389}105" "87264ABE4"]]
(println cusip (if (is-valid-cusip9? cusip) "valid" "invalid"))))
(println cusip (if (is-valid-cusip9? cusip) "valid" "invalid"))))
</syntaxhighlight>
</lang>


{{out}}
{{out}}
Line 989: Line 1,415:
68389X106 invalid
68389X106 invalid
68389X105 valid
68389X105 valid
EXTRACRD8 valid
EXTRACRD8 invalid
EXTRACRD9 valid
BADCUSIP! invalid
BADCUSIP! invalid
683&9X106 invalid
683&9X106 invalid
Line 995: Line 1,422:
683$9X106 invalid
683$9X106 invalid
68389}105 invalid
68389}105 invalid
87264ABE4 valid
</pre>
</pre>

=={{header|CLU}}==
<syntaxhighlight lang=clu>valid_cusip = proc (s: string) returns (bool)
own chars: string := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#"
if string$size(s) ~= 9 then return(false) end
sum: int := 0
for i: int in int$from_to(1,8) do
v: int := string$indexc(s[i], chars)-1
if v<0 then return(false) end
if i//2=0 then v := v*2 end
sum := sum + v/10 + v//10
end
check: int := (10 - sum // 10) // 10
return(check = string$indexc(s[9], chars)-1)
end valid_cusip

start_up = proc ()
po: stream := stream$primary_output()
cusips: array[string] := array[string]$[
"037833100",
"17275R102",
"38259P508",
"594918104",
"68389X106",
"68389X105"
]
for cusip: string in array[string]$elements(cusips) do
stream$puts(po, cusip || ": ")
if valid_cusip(cusip)
then stream$putl(po, "valid")
else stream$putl(po, "invalid")
end
end
end start_up</syntaxhighlight>
{{out}}
<pre>037833100: valid
17275R102: valid
38259P508: valid
594918104: valid
68389X106: invalid
68389X105: valid</pre>


=={{header|Common Lisp}}==
=={{header|Common Lisp}}==
<lang lisp>(defun char->value (c)
<syntaxhighlight lang=lisp>(defun char->value (c)
(cond ((digit-char-p c 36))
(cond ((digit-char-p c 36))
((char= c #\*) 36)
((char= c #\*) 36)
Line 1,020: Line 1,490:
(defun main ()
(defun main ()
(dolist (cusip '("037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105"))
(dolist (cusip '("037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105"))
(format t "~A: ~A~%" cusip (cusip-p cusip))))</lang>
(format t "~A: ~A~%" cusip (cusip-p cusip))))</syntaxhighlight>
{{out}}
{{out}}
<pre>037833100: T
<pre>037833100: T
Line 1,030: Line 1,500:


=={{header|D}}==
=={{header|D}}==
<lang D>import std.stdio;
<syntaxhighlight lang=D>import std.stdio;


void main(string[] args) {
void main(string[] args) {
Line 1,128: Line 1,598:
}
}


/// Invoke with `cusip 037833100 17275R102 38259P508 594918104 68389X106 68389X105`</lang>
/// Invoke with `cusip 037833100 17275R102 38259P508 594918104 68389X106 68389X105`</syntaxhighlight>


{{out}}
{{out}}
Line 1,138: Line 1,608:
68389X106 : Invalid
68389X106 : Invalid
68389X105 : Valid</pre>
68389X105 : Valid</pre>

=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|SysUtils,StdCtrls}}
Using sets to simplify string parsing

<syntaxhighlight lang="Delphi">
type TCUSIPInfo = record
ID,Company: string;
end;

var CUSIPArray: array [0..5] of TCUSIPInfo = (
(ID:'037833100'; Company: 'Apple Incorporated'),
(ID:'17275R102'; Company: 'Cisco Systems'),
(ID:'38259P508'; Company: 'Google Incorporated'),
(ID:'594918104'; Company: 'Microsoft Corporation'),
(ID:'68389X106'; Company: 'Oracle Corporation'),
(ID:'68389X105'; Company: 'Oracle Corporation'));

function IsValidCUSIP(Info: TCUSIPInfo): boolean;
{Calculate checksum on first 7 chars of CUSIP }
{And compare with the last char - the checksum char}
var I,V,Sum: integer;
var C: char;
begin
Sum:=0;
for I:=1 to Length(Info.ID)-1 do
begin
C:=Info.ID[I];
if C in ['0'..'9'] then V:=byte(C)-$30
else if C in ['A'..'Z'] then V:=(byte(C)-$40) + 9
else case C of
'*': V:=36;
'@': V:=37;
'#': V:=38;
end;
if (I and 1)=0 then V:=V*2;
Sum:=Sum + (V div 10) + (V mod 10);
end;
Sum:=(10 - (Sum mod 10)) mod 10;
Result:=StrToInt(Info.ID[Length(Info.ID)])=Sum;
end;


procedure TestCUSIPList(Memo: TMemo);
{Test every item in the CSUIP array}
var I: integer;
var S: string;
begin
for I:=0 to High(CUSIPArray) do
begin
if IsValidCUSIP(CUSIPArray[I]) then S:='Valid' else S:='Invalid';
Memo.Lines.Add(CUSIPArray[I].ID+' '+CUSIPArray[I].Company+': '+S);
end;
end;

</syntaxhighlight>
{{out}}
<pre>
037833100 Apple Incorporated: Valid
17275R102 Cisco Systems: Valid
38259P508 Google Incorporated: Valid
594918104 Microsoft Corporation: Valid
68389X106 Oracle Corporation: Invalid
68389X105 Oracle Corporation: Valid

</pre>



=={{header|Dyalect}}==
=={{header|Dyalect}}==
Line 1,143: Line 1,681:
{{trans|Go}}
{{trans|Go}}


<lang dyalect>func isCusip(s) {
<syntaxhighlight lang=dyalect>func isCusip(s) {
if s.len() != 9 { return false }
if s.Length() != 9 { return false }
var sum = 0
var sum = 0
for i in 0..7 {
for i in 0..7 {
Line 1,150: Line 1,688:
var v =
var v =
match c {
match c {
'0'..'9' => c.order() - 48,
'0'..'9' => c.Order() - 48,
'A'..'Z' => c.order() - 64,
'A'..'Z' => c.Order() - 55,
'*' => 36,
'*' => 36,
'@' => 37,
'@' => 37,
Line 1,160: Line 1,698:
sum += v / 10 + v % 10
sum += v / 10 + v % 10
}
}
s[8].order() - 48 == (10 - (sum % 10)) % 10
s[8].Order() - 48 == (10 - (sum % 10)) % 10
}
}
Line 1,180: Line 1,718:
}
}
print("\(candidate) -> \(b)")
print("\(candidate) -> \(b)")
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 1,190: Line 1,728:
68389X106 -> incorrect
68389X106 -> incorrect
68389X105 -> correct</pre>
68389X105 -> correct</pre>

=={{header|EasyLang}}==
<syntaxhighlight lang=easylang>
func check inp$ .
for i = 1 to 8
c = strcode substr inp$ i 1
if c >= 48 and c <= 57
v = c - 48
elif c >= 65 and c <= 91
v = c - 64 + 9
elif c = 42
v = 36
elif c = 64
v = 37
elif c = 35
v = 38
.
if i mod 2 = 0
v *= 2
.
sum += v div 10 + v mod 10
.
return if (10 - (sum mod 10)) mod 10 = number substr inp$ 9 1
.
for s$ in [ "037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105" ]
write s$ & " is "
if check s$ = 1
print "valid"
else
print "invalid"
.
.
</syntaxhighlight>



=={{header|Excel}}==
=={{header|Excel}}==
Line 1,198: Line 1,770:
(See [https://www.microsoft.com/en-us/research/blog/lambda-the-ultimatae-excel-worksheet-function/ LAMBDA: The ultimate Excel worksheet function])
(See [https://www.microsoft.com/en-us/research/blog/lambda-the-ultimatae-excel-worksheet-function/ LAMBDA: The ultimate Excel worksheet function])


<syntaxhighlight lang=lisp>=LAMBDA(s,
<lang lisp>ISCUSIP
=LAMBDA(s,
LET(
LET(
ns, VLOOKUP(
ns, VLOOKUP(
CHARS(s), CUSIPMAP, 2, FALSE
CHARS(s), CUSIPMAP, 2, FALSE
),
),

IF(9 = COLUMNS(ns),
AND(
9 = COLUMNS(ns),
LET(
LET(
firstEight, INITCOLS(ns),
firstEight, INITCOLS(ns),

ixs, SEQUENCE(1, 8),
ixs, SEQUENCE(1, 8),

evensDoubled, IF(ISEVEN(ixs),
evensDoubled, IF(ISEVEN(ixs),
2 * INDEX(firstEight, 1, ixs),
2 * INDEX(firstEight, 1, ixs),
INDEX(firstEight, 1, ixs)
INDEX(firstEight, 1, ixs)
),
),

LASTCOL(ns) = MOD(
LASTCOL(ns) = MOD(
10 - MOD(
10 - MOD(
Line 1,221: Line 1,793:
QUOTIENT(evensDoubled, 10),
QUOTIENT(evensDoubled, 10),
MOD(evensDoubled, 10)
MOD(evensDoubled, 10)
),
),
10
10
),
),
10
10
)
)
),
)
FALSE
)
)
)
)
Line 1,237: Line 1,808:
10;"B",11;"C",12;"D",13;"E",14;"F",15;"G",16;"H",17;"I",18;"J",19;"K",
10;"B",11;"C",12;"D",13;"E",14;"F",15;"G",16;"H",17;"I",18;"J",19;"K",
20;"L",21;"M",22;"N",23;"O",24;"P",25;"Q",26;"R",27;"S",28;"T",29;"U",
20;"L",21;"M",22;"N",23;"O",24;"P",25;"Q",26;"R",27;"S",28;"T",29;"U",
30;"V",31;"W",32;"X",33;"Y",34;"Z",35;"*",36;"@",37;"#",38}</lang>
30;"V",31;"W",32;"X",33;"Y",34;"Z",35;"*",36;"@",37;"#",38}</syntaxhighlight>


and also assuming the following generic bindings in the Name Manager for the WorkBook:
and also assuming the following generic bindings in the Name Manager for the WorkBook:


<lang lisp>CHARS
<syntaxhighlight lang=lisp>CHARS
=LAMBDA(s,
=LAMBDA(s,
MID(
MID(
Line 1,271: Line 1,842:
COLUMNS(xs)
COLUMNS(xs)
)
)
)</lang>
)</syntaxhighlight>


{{Out}}
{{Out}}
Line 1,312: Line 1,883:
|}
|}


=={{header|F_Sharp|F#}}==
<syntaxhighlight lang=fsharp>
// Validate CUSIP: Nigel Galloway. June 2nd., 2021
let fN=function n when n>47 && n<58->n-48 |n when n>64 && n<91->n-55 |42->36 |64->37 |_->38
let cD(n:string)=(10-(fst((n.[0..7])|>Seq.fold(fun(z,n)g->let g=(fN(int g))*(n+1) in (z+g/10+g%10,(n+1)%2))(0,0)))%10)%10=int(n.[8])-48
["037833100";"17275R102";"38259P508";"594918104";"68389X103";"68389X105"]|>List.iter(fun n->printfn "CUSIP %s is %s" n (if cD n then "valid" else "invalid"))
</syntaxhighlight>
{{out}}
<pre>
CUSIP 037833100 is valid
CUSIP 17275R102 is valid
CUSIP 38259P508 is valid
CUSIP 594918104 is valid
CUSIP 68389X103 is invalid
CUSIP 68389X105 is valid
Real: 00:00:00.009
</pre>
=={{header|Factor}}==
=={{header|Factor}}==
<lang factor>USING: combinators.short-circuit formatting kernel math
<syntaxhighlight lang=factor>USING: combinators.short-circuit formatting kernel math
math.parser qw regexp sequences unicode ;
math.parser qw regexp sequences unicode ;
IN: rosetta-code.cusip
IN: rosetta-code.cusip
Line 1,330: Line 1,918:


qw{ 037833100 17275R102 38259P508 594918104 68389X106 68389X105 }
qw{ 037833100 17275R102 38259P508 594918104 68389X106 68389X105 }
[ dup cusip? "correct" "incorrect" ? "%s -> %s\n" printf ] each</lang>
[ dup cusip? "correct" "incorrect" ? "%s -> %s\n" printf ] each</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 1,346: Line 1,934:
The source does not bother with the MODULE protocol of F90 and later, and so the type of function CUSIPCHECK must be declared in all routines wishing to invoke it. However, the F90 feature of having the END statement of a subroutine or function give its name is to valuable to ignore. The function returns a character code rather than an integer, since the presumption is that it is to be compared to the check character of the code being inspected, which is known as a character not an integer. This means some blather when extracting the eight characters to be presented to CUSIPCHECK and comparing the result to the ninth character, but the test can be done in one expression.
The source does not bother with the MODULE protocol of F90 and later, and so the type of function CUSIPCHECK must be declared in all routines wishing to invoke it. However, the F90 feature of having the END statement of a subroutine or function give its name is to valuable to ignore. The function returns a character code rather than an integer, since the presumption is that it is to be compared to the check character of the code being inspected, which is known as a character not an integer. This means some blather when extracting the eight characters to be presented to CUSIPCHECK and comparing the result to the ninth character, but the test can be done in one expression.


There is no checking that only valid characters are presented, nor that eight-character codes only are offered, though the compiler might complain if the function were to be invoked with a text literal of the wrong size. In the absence of such checks, there need be no added complications to support a scheme for reporting such errors. <lang Fortran> CHARACTER*1 FUNCTION CUSIPCHECK(TEXT) !Determines the check sum character.
There is no checking that only valid characters are presented, nor that eight-character codes only are offered, though the compiler might complain if the function were to be invoked with a text literal of the wrong size. In the absence of such checks, there need be no added complications to support a scheme for reporting such errors. <syntaxhighlight lang=Fortran> CHARACTER*1 FUNCTION CUSIPCHECK(TEXT) !Determines the check sum character.
Committee on Uniform Security Identification Purposes, of the American (i.e. USA) Bankers' Association.
Committee on Uniform Security Identification Purposes, of the American (i.e. USA) Bankers' Association.
CHARACTER*8 TEXT !Specifically, an eight-symbol code.
CHARACTER*8 TEXT !Specifically, an eight-symbol code.
Line 1,379: Line 1,967:
END DO
END DO


END</lang>
END</syntaxhighlight>


Output: standard output is to I/O unit 6, and free-format (the *) will suffice for this. Each line output starts with a space (in case it is to go to a lineprinter, with carriage control), which is convenient for layout here.
Output: standard output is to I/O unit 6, and free-format (the *) will suffice for this. Each line output starts with a space (in case it is to go to a lineprinter, with carriage control), which is convenient for layout here.
Line 1,391: Line 1,979:
This would have worked first time, except that a fymgre frmble caused the omission of the digit 2 from the text of VALID. The benefits of checking checksums reach to unexpected places!
This would have worked first time, except that a fymgre frmble caused the omission of the digit 2 from the text of VALID. The benefits of checking checksums reach to unexpected places!


=={{header|FreeBASIC}}==
<lang freebasic>' version 04-04-2017
' compile with: fbc -s console


=={{header|FutureBasic}}==
sub cusip(input_str As String)
<syntaxhighlight lang="futurebasic">
include "NSLog.incl"


local fn VerifyCUSIP( cusipStr as CFStringRef ) as CFStringRef
Print input_str;
NSUInteger i, v, sum = 0, count = len(cusipStr)
If Len(input_str) <> 9 Then
CFStringRef resultStr
Print " length is incorrect, invalid cusip"
Return
if count != 9 then exit fn = @"Invalid length"
End If
for i = 0 to 7
unichar x = fn StringCharacterAtIndex( cusipStr, i )
select x
case _"*" : v = 36
case _"@" : v = 37
case _"#" : v = 38
case else
if ( x >= _"0" and x <= _"9" )
v = x - _"0"
else
if ( x >= _"A" and x <= _"Z" )
v = x - _"A" + 10
else
exit fn = fn StringWithFormat( @"Invalid character: %c", x )
end if
end if
end select
if ( i and 1 ) then v = v * 2
sum += (v / 10) + (v mod 10)
next
sum = ((10-(sum mod 10)) mod 10)
if (sum == ( fn StringCharacterAtIndex( cusipStr, 8 ) - _"0" ))
resultStr = @"Valid"
else
resultStr = @"Invalid"
end If
end fn = resultStr


NSLog( @"0378331009: %@", fn VerifyCUSIP( @"0378331009" ) ) // Invalid length expected
Dim As Long i, v , sum
NSLog( @"037833100: %@", fn VerifyCUSIP( @"037833100" ) ) // Valid expected
Dim As UByte x
NSLog( @"17275R102: %@", fn VerifyCUSIP( @"17275R102" ) ) // Valid expected
NSLog( @"38259P508: %@", fn VerifyCUSIP( @"38259P508" ) ) // Valid expected
NSLog( @"594918104: %@", fn VerifyCUSIP( @"594918104" ) ) // Valid expected
NSLog( @"68389X106: %@", fn VerifyCUSIP( @"68389X106" ) ) // Invalid expected
NSLog( @"68389X105: %@", fn VerifyCUSIP( @"68389X105" ) ) // Valid expected
NSLog( @"683&9X105: %@", fn VerifyCUSIP( @"683&9X105" ) ) // Invalid character expected: &


HandleEvents
For i = 1 To 8
</syntaxhighlight>
x = input_str[i-1]
{{output}}
Select Case x
<pre>
Case Asc("0") To Asc("9")
0378331009: Invalid length
v = x - Asc("0")
037833100: Valid
Case Asc("A") To Asc("Z")
17275R102: Valid
v = x - Asc("A") + 1 + 9
38259P508: Valid
Case Asc("*")
594918104: Valid
v= 36
68389X106: Invalid
Case Asc("@")
68389X105: Valid
v = 37
683&9X105: Invalid character: &
Case Asc("#")
</pre>
v = 38
Case Else
Print " found a invalid character, invalid cusip"
return
End Select

If (i And 1) = 0 Then v = v * 2
sum = sum + v \ 10 + v Mod 10
Next

sum = (10 - (sum Mod 10)) Mod 10
If sum = (input_str[8] - Asc("0")) Then
Print " is valid"
Else
Print " is invalid"
End If

End Sub

' ------=< MAIN >=------

Data "037833100", "17275R102", "38259P508"
Data "594918104", "68389X106", "68389X105"

Dim As String input_str

Print
For i As Integer = 1 To 6
Read input_str
cusip(input_str)
Next

' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End</lang>
{{out}}
<pre>037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
68389X105 is valid</pre>


=={{header|Go}}==
=={{header|Go}}==
<lang go>package main
<syntaxhighlight lang=go>package main


import "fmt"
import "fmt"
Line 1,478: Line 2,059:
v = int(c) - 48
v = int(c) - 48
case c >= 'A' && c <= 'Z':
case c >= 'A' && c <= 'Z':
v = int(c) - 64
v = int(c) - 55
case c == '*':
case c == '*':
v = 36
v = 36
Line 1,514: Line 2,095:
}
}
}
}
</syntaxhighlight>
</lang>


{{out}}
{{out}}
Line 1,528: Line 2,109:
=={{header|Groovy}}==
=={{header|Groovy}}==
{{trans|Java}}
{{trans|Java}}
<lang groovy>class Cusip {
<syntaxhighlight lang=groovy>class Cusip {
private static Boolean isCusip(String s) {
private static Boolean isCusip(String s) {
if (s.length() != 9) return false
if (s.length() != 9) return false
Line 1,539: Line 2,120:
v = c - 48
v = c - 48
} else if (c >= ('A' as char) && c <= ('Z' as char)) {
} else if (c >= ('A' as char) && c <= ('Z' as char)) {
v = c - 64 // lower case letters apparently invalid
v = c - 55 // lower case letters apparently invalid
} else if (c == '*' as char) {
} else if (c == '*' as char) {
v = 36
v = 36
Line 1,567: Line 2,148:
}
}
}
}
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>037833100 -> correct
<pre>037833100 -> correct
Line 1,577: Line 2,158:


=={{header|Haskell}}==
=={{header|Haskell}}==
<lang haskell>import Data.List(elemIndex)
<syntaxhighlight lang=haskell>import Data.List(elemIndex)


data Result = Valid | BadCheck | TooLong | TooShort | InvalidContent deriving Show
data Result = Valid | BadCheck | TooLong | TooShort | InvalidContent deriving Show
Line 1,620: Line 2,201:
]
]


main = mapM_ putStrLn (fmap (\s -> s ++ ": " ++ show (checkCUSIP s)) testData)</lang>
main = mapM_ putStrLn (fmap (\s -> s ++ ": " ++ show (checkCUSIP s)) testData)</syntaxhighlight>


{{out}}
{{out}}
Line 1,631: Line 2,212:
</pre>
</pre>


Or, making some alternative selections from Haskell's rich libraries:
Or, picking some other possibilities from Haskell's rich libraries:
<lang Haskell>import qualified Data.Map as M (Map, fromList, lookup)
<syntaxhighlight lang=Haskell>import qualified Data.Map as M (Map, fromList, lookup)
import Data.Maybe (fromMaybe)
import Data.Maybe (fromMaybe)

-------------------------- CUSIP -------------------------


cusipMap :: M.Map Char Int
cusipMap :: M.Map Char Int
cusipMap =
cusipMap = M.fromList $ zip (['0' .. '9'] ++ ['A' .. 'Z'] ++ "*@#") [0 ..]
M.fromList $
zip (['0' .. '9'] <> ['A' .. 'Z'] <> "*@#") [0 ..]


cusipValid :: String -> Bool
cusipValid :: String -> Bool
cusipValid s =
cusipValid s =
let ns = (fromMaybe [] . traverse (`M.lookup` cusipMap)) s
let ns = (fromMaybe [] . traverse (`M.lookup` cusipMap)) s
in (9 == length ns) &&
in (9 == length ns)
let qrSum =
&& let qrSum =
sum $
sum $
([quot, rem] <*> zipWith id (cycle [id, (* 2)]) (take 8 ns)) <*> [10]
( [quot, rem]
in last ns == rem (10 - rem qrSum 10) 10
<*> zipWith
id
(cycle [id, (* 2)])
(take 8 ns)
)
<*> [10]
in last ns == rem (10 - rem qrSum 10) 10


--------------------------- TEST -------------------------
main :: IO ()
main :: IO ()
main =
main =
mapM_
mapM_
(print . ((,) <*> cusipValid))
(print . ((,) <*> cusipValid))
[ "037833100"
[ "037833100",
, "17275R102"
"17275R102",
, "38259P508"
"38259P508",
, "594918104"
"594918104",
, "68389X106"
"68389X106",
, "68389X105"
"68389X105"
]</lang>
]</syntaxhighlight>
{{Out}}
{{Out}}
<pre>("037833100",True)
<pre>("037833100",True)
Line 1,667: Line 2,259:


=={{header|Icon}} and {{header|Unicon}}==
=={{header|Icon}} and {{header|Unicon}}==
<lang Icon># cusip.icn -- Committee on Uniform Security Identification Procedures
<syntaxhighlight lang=Icon># cusip.icn -- Committee on Uniform Security Identification Procedures


procedure main()
procedure main()
Line 1,706: Line 2,298:
t[chars[n]] := (n - 1)
t[chars[n]] := (n - 1)
return t
return t
end</lang>
end</syntaxhighlight>


{{out}}<pre>037833100 : valid.
{{out}}<pre>037833100 : valid.
Line 1,718: Line 2,310:
=={{header|J}}==
=={{header|J}}==
One-liner:
One-liner:
<lang j> ccd =. 10 | 10 - 10 | [: +/ [: , 10 (#.^:_1) (8 $ 1 2) * '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#' i. ]
<syntaxhighlight lang=j> ccd =. 10 | 10 - 10 | [: +/ [: , 10 (#.^:_1) (8 $ 1 2) * '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#' i. ]
ccd '68389X10'
ccd '68389X10'
5</lang>
5</syntaxhighlight>


More verbose version that checks for correct input:
More verbose version that checks for correct input:
<lang j> CUSIPcheckdigit =. 3 : 0
<syntaxhighlight lang=j> CUSIPcheckdigit =. 3 : 0
assert. 8 = $ y NB. Only accept an 8-element long list
assert. 8 = $ y NB. Only accept an 8-element long list
assert. */ y e. '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#' NB. Only accept characters from the list of 38
assert. */ y e. '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#' NB. Only accept characters from the list of 38
Line 1,732: Line 2,324:
)
)
addCUSIPcheckdigit =: , CUSIPcheckdigit
addCUSIPcheckdigit =: , CUSIPcheckdigit
verifyCUSIPcheckdigit =: {: = CUSIPcheckdigit@}:</lang>
verifyCUSIPcheckdigit =: {: = CUSIPcheckdigit@}:</syntaxhighlight>


Examples:
Examples:
<lang j> addCUSIPcheckdigit '68389X10'
<syntaxhighlight lang=j> addCUSIPcheckdigit '68389X10'
68389X105
68389X105
verifyCUSIPcheckdigit '68389X106'
verifyCUSIPcheckdigit '68389X106'
Line 1,750: Line 2,342:
│68389X106│0│
│68389X106│0│
│68389X105│1│
│68389X105│1│
└─────────┴─┘</lang>
└─────────┴─┘</syntaxhighlight>


=={{header|Java}}==
=={{header|Java}}==
{{trans|Kotlin}}
{{trans|Kotlin}}
Uses Java 9
Uses Java 9
<lang Java>import java.util.List;
<syntaxhighlight lang=Java>import java.util.List;


public class Cusip {
public class Cusip {
Line 1,768: Line 2,360:
v = c - 48;
v = c - 48;
} else if (c >= 'A' && c <= 'Z') {
} else if (c >= 'A' && c <= 'Z') {
v = c - 64; // lower case letters apparently invalid
v = c - 55; // lower case letters apparently invalid
} else if (c == '*') {
} else if (c == '*') {
v = 36;
v = 36;
Line 1,786: Line 2,378:
public static void main(String[] args) {
public static void main(String[] args) {
List<String> candidates = List.of(
List<String> candidates = List.of(
"037833100",
"037833100", "17275R102", "38259P508", "594918104", "68389X106", "68389X105", "EXTRACRD8",
"EXTRACRD9", "BADCUSIP!", "683&9X106", "68389x105", "683$9X106", "68389}105", "87264ABE4"
"17275R102",
"38259P508",
"594918104",
"68389X106",
"68389X105"
);
);
for (String candidate : candidates) {
for (String candidate : candidates) {
Line 1,797: Line 2,385:
}
}
}
}
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>037833100 -> correct
<pre>037833100 -> correct
Line 1,805: Line 2,393:
68389X106 -> incorrect
68389X106 -> incorrect
68389X105 -> correct
68389X105 -> correct
EXTRACRD8 -> incorrect
EXTRACRD9 -> correct
BADCUSIP! -> incorrect
683&9X106 -> incorrect
68389x105 -> incorrect
683$9X106 -> incorrect
68389}105 -> incorrect
87264ABE4 -> correct
</pre>
</pre>


=={{header|JavaScript}}==
=={{header|JavaScript}}==
<lang javascript>(() => {
<syntaxhighlight lang=javascript>(() => {
'use strict';
'use strict';


Line 2,236: Line 2,832:
// MAIN ---
// MAIN ---
return main();
return main();
})();</lang>
})();</syntaxhighlight>
{{Out}}
{{Out}}
<pre>037833100 -> true
<pre>037833100 -> true
Line 2,244: Line 2,840:
68389X106 -> false
68389X106 -> false
68389X105 -> true</pre>
68389X105 -> true</pre>

=={{header|jq}}==
''Adapted from [[#Wren|Wren]]''
{{works with|jq}}
'''Also works with gojq, the Go implementation of jq, and with jackson-jq and fq.'''
<syntaxhighlight lang=jq>
def isCusip:
length == 9 and
explode as $s
| {sum: 0, i: 0}
| until(. == false or .i == 8;
$s[.i] as $c
| (if ($c >= 48 and $c <= 57) # '0' to '9'
then $c - 48
elif ($c >= 65 and $c <= 90) # 'A' to 'Z'
then $c - 55
elif $c == 42 # '*'
then 36
elif $c == 64 # '@'
then 37
elif $c == 35 # '#'
then 38
else false # return false
end ) as $v
| if $v == false then false
else # check if odd as using 0-based indexing
(if (.i%2 == 1) then 2 * $v else $v end) as $v
| .sum += (($v/10)|floor) + $v%10
| .i += 1
end )
| if . == false then false
else $s[8] - 48 == (10 - (.sum%10)) % 10
end;

def candidates: [
"037833100",
"17275R102",
"38259P508",
"594918104",
"68389X106",
"68389X105"
];

candidates[]
| "\(.) -> \(if isCusip then "correct" else "incorrect" end)"
</syntaxhighlight>
{{output}}
<pre>
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct
</pre>


=={{header|Julia}}==
=={{header|Julia}}==
{{works with|Julia|0.6}}
{{works with|Julia|0.6}}


<lang julia>module CUSIP
<syntaxhighlight lang=julia>module CUSIP


function _lastdigitcusip(input::AbstractString)
function _lastdigitcusip(input::AbstractString)
Line 2,280: Line 2,931:
for code in ("037833100", "17275R102", "38259P508", "594918104", "68389X106", "68389X105")
for code in ("037833100", "17275R102", "38259P508", "594918104", "68389X106", "68389X105")
println("$code is ", CUSIP.checkdigit(code) ? "correct." : "not correct.")
println("$code is ", CUSIP.checkdigit(code) ? "correct." : "not correct.")
end</lang>
end</syntaxhighlight>


{{out}}
{{out}}
Line 2,291: Line 2,942:


=={{header|Kotlin}}==
=={{header|Kotlin}}==
<lang scala>// version 1.1.0
<syntaxhighlight lang=scala>// version 1.1.0


fun isCusip(s: String): Boolean {
fun isCusip(s: String): Boolean {
Line 2,300: Line 2,951:
var v = when (c) {
var v = when (c) {
in '0'..'9' -> c.toInt() - 48
in '0'..'9' -> c.toInt() - 48
in 'A'..'Z' -> c.toInt() - 64 // lower case letters apparently invalid
in 'A'..'Z' -> c.toInt() - 55 // lower case letters apparently invalid
'*' -> 36
'*' -> 36
'@' -> 37
'@' -> 37
Line 2,323: Line 2,974:
for (candidate in candidates)
for (candidate in candidates)
println("$candidate -> ${if(isCusip(candidate)) "correct" else "incorrect"}")
println("$candidate -> ${if(isCusip(candidate)) "correct" else "incorrect"}")
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 2,337: Line 2,988:
=={{header|langur}}==
=={{header|langur}}==
If we don't strictly follow the pseudo-code, we can do this.
If we don't strictly follow the pseudo-code, we can do this.
<syntaxhighlight lang=langur>val .isCusip = fn(.s) {

if .s is not string or len(.s) != 9 {
{{works with|langur|0.8.5}}
<lang langur>val .isCusip = f(.s) {
if not isString(.s) or len(.s) != 9 {
return false
return false
}
}


val .basechars = cp2s('0'..'9') ~ cp2s('A'..'Z') ~ "*@#"
val .basechars = '0'..'9' ~ 'A'..'Z' ~ "*@#"


val .sum = for[=0] .i of 8 {
val .sum = for[=0] .i of 8 {
Line 2,350: Line 2,999:
if not .v: return false
if not .v: return false
.v = .v[1]-1
.v = .v[1]-1
if .i div 2: .v x= 2
if .i div 2: .v *= 2
_for += .v \ 10 + .v rem 10
_for += .v \ 10 + .v rem 10
}
}
Line 2,357: Line 3,006:
}
}


val .candidates = w/037833100 17275R102 38259P508 594918104 68389X106 68389X105/
val .candidates = fw/037833100 17275R102 38259P508 594918104 68389X106 68389X105/


for .c in .candidates {
for .c in .candidates {
writeln .c, ": ", if(.isCusip(.c): "good" ; "bad")
writeln .c, ": ", if(.isCusip(.c): "good" ; "bad")
}</lang>
}</syntaxhighlight>


Following the pseudo-code would look more like the following.
Following the pseudo-code would look more like the following.

{{works with|langur|0.8.5}}
{{trans|Go}}
{{trans|Go}}
<lang langur>val .isCusip = f(.s) {
<syntaxhighlight lang=langur>val .isCusip = fn(.s) {
if not isString(.s) or len(.s) != 9 {
if .s is not string or len(.s) != 9 {
return false
return false
}
}
Line 2,376: Line 3,023:
var .v = 0
var .v = 0


given .c {
switch[and] .c {
# note: default op between conditions "and"
# Use "case or" to make given act like a switch in some other languages.
case >= '0', <= '9':
case >= '0', <= '9':
.v = .c-'0'
.v = .c-'0'
Line 2,392: Line 3,037:
}
}


if .i div 2: .v x= 2
if .i div 2: .v *= 2
_for += .v \ 10 + .v rem 10
_for += .v \ 10 + .v rem 10
}
}
Line 2,403: Line 3,048:
for .c in .candidates {
for .c in .candidates {
writeln .c, ": ", if(.isCusip(.c): "good" ; "bad")
writeln .c, ": ", if(.isCusip(.c): "good" ; "bad")
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 2,415: Line 3,060:
=={{header|Lua}}==
=={{header|Lua}}==
The checkDigit function is a line-for-line translation of the pseudo-code algorithm.
The checkDigit function is a line-for-line translation of the pseudo-code algorithm.
<lang Lua>function checkDigit (cusip)
<syntaxhighlight lang=Lua>function checkDigit (cusip)
if #cusip ~= 8 then return false end
if #cusip ~= 8 then return false end
Line 2,424: Line 3,069:
v = tonumber(c)
v = tonumber(c)
elseif c:match("%a") then
elseif c:match("%a") then
p = string.byte(c) - 64
p = string.byte(c) - 55
v = p + 9
v = p + 9
elseif c == "*" then
elseif c == "*" then
Line 2,458: Line 3,103:
print("INVALID")
print("INVALID")
end
end
end</lang>
end</syntaxhighlight>
{{out}}
{{out}}
<pre>037833100: VALID
<pre>037833100: VALID
Line 2,466: Line 3,111:
68389X106: INVALID
68389X106: INVALID
68389X105: VALID</pre>
68389X105: VALID</pre>

=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang=Mathematica>ClearAll[Cusip]
rules = Thread[(ToString /@ Range[0, 9]) -> Range[0, 9]]~Join~
Thread[CharacterRange["A", "Z"] -> Range[26] + 9]~Join~
Thread[Characters["*@#"] -> {36, 37, 38}];
Cusip[cusip_String] := Module[{s = cusip, sum = 0, c, value, check},
If[StringLength[s] != 9,
Print["Cusip must be 9 characters!"];
False
,
s = Characters[ToUpperCase[s]];
Do[
c = s[[i]];
value = c /. rules;
If[EvenQ[i], value *= 2];
sum += Floor[value/10] + Mod[value, 10];
,
{i, 8}
];
check = Mod[(10 - Mod[sum, 10]), 10];
s[[-1]] === ToString[check]
]
]
Cusip /@ {"037833100", "17275R102", "38259P508", "594918104", "68389X106", "68389X105"}</syntaxhighlight>
{{out}}
<pre>{True, True, True, True, False, True}</pre>

=={{header|MiniScript}}==
<syntaxhighlight lang="miniscript">isCusip = function(s)
if s.len != 9 then return false
sum = 0
for i in range(0, 7)
c = s[i]
v = 0
if c >= "0" and c <= "9" then
v = code(c) - 48
else if c >= "A" and c <= "Z" then
v = code(c) - 55
else if c == "*" then
v = 36
else if c == "@" then
v = 37
else if c == "#" then
v = 38
else
return false
end if
if i%2 == 1 then v *= 2 // check if odd as using 0-based indexing
sum += floor(v/10) + v%10
end for
return code(s[8]) - 48 == (10 - (sum%10)) % 10
end function

candidates = [
"037833100", "17275R102", "38259P508",
"594918104", "68389X106", "68389X105",
]
for candidate in candidates
s = "valid"
if not isCusip(candidate) then s = "invalid"
print candidate + " -> " + s
end for</syntaxhighlight>

{{out}}
<pre>037833100 -> valid
17275R102 -> valid
38259P508 -> valid
594918104 -> valid
68389X106 -> invalid
68389X105 -> valid
</pre>


=={{header|Modula-2}}==
=={{header|Modula-2}}==
<lang modula2>MODULE CUSIP;
<syntaxhighlight lang=modula2>MODULE CUSIP;
FROM FormatString IMPORT FormatString;
FROM FormatString IMPORT FormatString;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;
Line 2,543: Line 3,260:


ReadChar
ReadChar
END CUSIP.</lang>
END CUSIP.</syntaxhighlight>
{{out}}
{{out}}
<pre>CUSIP Verdict
<pre>CUSIP Verdict
Line 2,554: Line 3,271:


=={{header|Nanoquery}}==
=={{header|Nanoquery}}==
<lang Nanoquery>def cusip_checksum(cusip)
<syntaxhighlight lang=Nanoquery>def cusip_checksum(cusip)
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
num = "0123456789"
num = "0123456789"
Line 2,591: Line 3,308:
end
end
end
end
end</lang>
end</syntaxhighlight>


{{out}}
{{out}}
Line 2,602: Line 3,319:


=={{header|Nim}}==
=={{header|Nim}}==
<lang Nim>import strutils
<syntaxhighlight lang=Nim>import strutils


proc cusipCheck(cusip: string): bool =
proc cusipCheck(cusip: string): bool =
Line 2,642: Line 3,359:
echo code, ": ", if cusipCheck(code): "Valid" else: "Invalid"
echo code, ": ", if cusipCheck(code): "Valid" else: "Invalid"


main()</lang>
main()</syntaxhighlight>


{{out}}
{{out}}
Line 2,655: Line 3,372:
=={{header|Objeck}}==
=={{header|Objeck}}==
{{trans|Kotlin}}
{{trans|Kotlin}}
<lang Objeck>class Cusip {
<syntaxhighlight lang=Objeck>class Cusip {
function : native : IsCusip(s : String) ~ Bool {
function : native : IsCusip(s : String) ~ Bool {
if(s->Size() <> 9) {
if(s->Size() <> 9) {
Line 2,669: Line 3,386:
v := c - 48;
v := c - 48;
} else if (c >= 'A' & c <= 'Z') {
} else if (c >= 'A' & c <= 'Z') {
v := c - 64; # lower case letters apparently invalid
v := c - 55; # lower case letters apparently invalid
} else if (c = '*') {
} else if (c = '*') {
v := 36;
v := 36;
Line 2,712: Line 3,429:
};
};
}
}
}</lang>
}</syntaxhighlight>


Output:
Output:
Line 2,726: Line 3,443:
=={{header|Perl}}==
=={{header|Perl}}==


<lang perl>$cv{$_} = $i++ for '0'..'9', 'A'..'Z', '*', '@', '#';
<syntaxhighlight lang=perl>$cv{$_} = $i++ for '0'..'9', 'A'..'Z', '*', '@', '#';


sub cusip_check_digit {
sub cusip_check_digit {
Line 2,752: Line 3,469:
);
);


print "$_ $test_data{$_}" . cusip_check_digit($_) . "\n" for sort keys %test_data;</lang>
print "$_ $test_data{$_}" . cusip_check_digit($_) . "\n" for sort keys %test_data;</syntaxhighlight>
{{out}}
{{out}}
<pre>037833100 Apple Incorporated
<pre>037833100 Apple Incorporated
Line 2,762: Line 3,479:


=={{header|Phix}}==
=={{header|Phix}}==
<!--<lang Phix>(phixonline)-->
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #004080;">sequence</span> <span style="color: #000000;">cch</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">cch</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
Line 2,803: Line 3,520:
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s : %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"invalid"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"valid"</span><span style="color: #0000FF;">}[</span><span style="color: #000000;">CusipCheckDigit</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s : %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">"invalid"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"valid"</span><span style="color: #0000FF;">}[</span><span style="color: #000000;">CusipCheckDigit</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
{{out}}
{{out}}
<pre>
<pre>
Line 2,815: Line 3,532:


=={{header|PHP}}==
=={{header|PHP}}==
<lang PHP>function IsCusip(string $s) {
<syntaxhighlight lang=PHP>function IsCusip(string $s) {
if (strlen($s) != 9) return false;
if (strlen($s) != 9) return false;
$sum = 0;
$sum = 0;
Line 2,853: Line 3,570:
"68389X105");
"68389X105");


foreach ($cusips as $cusip) echo $cusip . " -> " . (IsCusip($cusip) ? "valid" : "invalid") . "\n";</lang>
foreach ($cusips as $cusip) echo $cusip . " -> " . (IsCusip($cusip) ? "valid" : "invalid") . "\n";</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 2,864: Line 3,581:


=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
<lang PicoLisp>(de cusip (Str)
<syntaxhighlight lang=PicoLisp>(de cusip (Str)
(let (Str (mapcar char (chop Str)) S 0)
(let (Str (mapcar char (chop Str)) S 0)
(for (I . C) (head 8 Str)
(for (I . C) (head 8 Str)
Line 2,892: Line 3,609:
"38259P508"
"38259P508"
"68389X106"
"68389X106"
"68389X105" ) ) )</lang>
"68389X105" ) ) )</syntaxhighlight>
{{out}}
{{out}}
<pre>(T T T NIL T)</pre>
<pre>(T T T NIL T)</pre>


=={{header|PowerShell}}==
=={{header|PowerShell}}==
<lang PowerShell>
<syntaxhighlight lang=PowerShell>
function Get-CheckDigitCUSIP {
function Get-CheckDigitCUSIP {
[CmdletBinding()]
[CmdletBinding()]
Line 2,946: Line 3,663:
"@ -split "`n"
"@ -split "`n"
$data |%{ Test-IsCUSIP $_.Split("`t")[0] }
$data |%{ Test-IsCUSIP $_.Split("`t")[0] }
</lang>{{out}}<pre>
</syntaxhighlight>{{out}}<pre>
True
True
True
True
Line 2,959: Line 3,676:
Requires Python 3.6 for the string template literal in the print statement.
Requires Python 3.6 for the string template literal in the print statement.


<lang python>#!/usr/bin/env python3
<syntaxhighlight lang=python>#!/usr/bin/env python3


import math
import math
Line 3,001: Line 3,718:
for code in codes:
for code in codes:
print(f'{code} -> {cusip_check(code)}')
print(f'{code} -> {cusip_check(code)}')
</syntaxhighlight>
</lang>
Output:
Output:
<pre>037833100 -> True
<pre>037833100 -> True
Line 3,014: Line 3,731:
{{Works with|Python|3.7}}
{{Works with|Python|3.7}}
Composing a set of pure functions, including a number of general and reusable abstractions:
Composing a set of pure functions, including a number of general and reusable abstractions:
<lang python>'''CUSIP'''
<syntaxhighlight lang=python>'''CUSIP'''


from itertools import (cycle, islice, starmap)
from itertools import (cycle, islice, starmap)
Line 3,173: Line 3,890:
# MAIN ---
# MAIN ---
if __name__ == '__main__':
if __name__ == '__main__':
main()</lang>
main()</syntaxhighlight>
{{Out}}
{{Out}}
<pre>Test for validity as a CUSIP string:
<pre>Test for validity as a CUSIP string:
Line 3,183: Line 3,900:
'68389X106' -> False
'68389X106' -> False
'68389X105' -> True</pre>
'68389X105' -> True</pre>

=={{header|Quackery}}==

<syntaxhighlight lang=Quackery> [ -1 split 0 peek char 0 -
swap 0 swap
witheach
[ [ dup char 0 char 9 1+ within iff
[ char 0 - ] done
dup char A char Z 1+ within iff
[ char A - 10 + ] done
dup char * = iff
[ drop 36 ] done
dup char @ = iff
[ drop 37 ] done
dup char # = iff
[ drop 38 ] done
$ "Unexpected character '" swap
join $ "' in CUSIP." join fail ]
i^ 1 & if [ 2 * ]
10 /mod + + ]
10 mod 10 swap - 10 mod = ] is cusip ( $ --> b )
[ dup echo$ cusip iff
[ say " is correct." ]
else [ say " is incorrect." ]
cr ] is task ( $ --> )
$ "037833100 17275R102 38259P508 594918104 68389X106 68389X105"
nest$ witheach task</syntaxhighlight>

{{out}}

<pre>037833100 is correct.
17275R102 is correct.
38259P508 is correct.
594918104 is correct.
68389X106 is incorrect.
68389X105 is correct.
</pre>


=={{header|Racket}}==
=={{header|Racket}}==


<lang racket>#lang racket
<syntaxhighlight lang=racket>#lang racket
(require srfi/14)
(require srfi/14)


Line 3,222: Line 3,978:
(check-true (CUSIP? "594918104"))
(check-true (CUSIP? "594918104"))
(check-false (CUSIP? "68389X106"))
(check-false (CUSIP? "68389X106"))
(check-true (CUSIP? "68389X105")))</lang>
(check-true (CUSIP? "68389X105")))</syntaxhighlight>


no output indicates all tests passed.
no output indicates all tests passed.
Line 3,230: Line 3,986:
{{works with|Rakudo|2017.01}}
{{works with|Rakudo|2017.01}}


<lang perl6>sub divmod ($v, $r) { $v div $r, $v mod $r }
<syntaxhighlight lang=raku line>sub divmod ($v, $r) { $v div $r, $v mod $r }
my %chr = (flat 0..9, 'A'..'Z', <* @ #>) Z=> 0..*;
my %chr = (flat 0..9, 'A'..'Z', <* @ #>) Z=> 0..*;


Line 3,247: Line 4,003:
68389X106
68389X106
68389X105
68389X105
></lang>
></syntaxhighlight>
{{out}}
{{out}}
<pre>037833100: True
<pre>037833100: True
Line 3,258: Line 4,014:
=={{header|REXX}}==
=={{header|REXX}}==
===idiomatic===
===idiomatic===
<lang rexx>/*REXX program validates that the last digit (the check digit) of a CUSIP is valid. */
<syntaxhighlight lang=rexx>/*REXX program validates that the last digit (the check digit) of a CUSIP is valid. */
@.=
@.=
parse arg @.1 .
parse arg @.1 .
Line 3,289: Line 4,045:
$=$ + #%10 + #//10
$=$ + #%10 + #//10
end /*k*/
end /*k*/
return (10- $//10) // 10</lang>
return (10- $//10) // 10</syntaxhighlight>
'''output''' &nbsp; when using the default input:
'''output''' &nbsp; when using the default input:
<pre>
<pre>
Line 3,301: Line 4,057:


===conciser function===
===conciser function===
<lang rexx>/*REXX program validates that the last digit (the check digit) of a CUSIP is valid. */
<syntaxhighlight lang=rexx>/*REXX program validates that the last digit (the check digit) of a CUSIP is valid. */
@.=
@.=
parse arg @.1 .
parse arg @.1 .
Line 3,326: Line 4,082:
$=$ + #%10 + #//10
$=$ + #%10 + #//10
end /*k*/
end /*k*/
return (10-$//10) // 10</lang>
return (10-$//10) // 10</syntaxhighlight>
'''output''' &nbsp; is the same as the idiomatic REXX version. <br><br>
'''output''' &nbsp; is the same as the idiomatic REXX version. <br><br>


=={{header|Ring}}==
=={{header|Ring}}==
<lang ring>
<syntaxhighlight lang=ring>
# Project : CUSIP
# Project : CUSIP


Line 3,359: Line 4,115:
ok
ok
if x >= ascii("A") and x <= ascii("Z")
if x >= ascii("A") and x <= ascii("Z")
v = x - 64
v = x - 55
flag = 1
flag = 1
ok
ok
Line 3,388: Line 4,144:
see inputstr + " is invalid" + nl
see inputstr + " is invalid" + nl
ok
ok
</syntaxhighlight>
</lang>
Output:
Output:
<pre>
<pre>
Line 3,397: Line 4,153:
68389X106 is invalid
68389X106 is invalid
68389X105 is valid
68389X105 is valid
</pre>

=={{header|RPL}}==
{{works with|Halcyon Calc|4.2.7}}
{| class="wikitable"
! RPL code
! Comment
|-
|
SWAP ROT DUP2 ≤ OVER 5 ROLL ≤ AND
SWAP NUM ROT NUM - 1 + 0 '''IFTE'''
≫ ''''BTWEEN'''' STO
0
1 8 '''FOR''' j
OVER j DUP SUB → c
≪ '''IF''' c "0" "9" '''BTWEEN'''
'''THEN''' LAST 1 -
'''ELSE IF''' c "A" "Z" '''BTWEEN'''
'''THEN''' LAST
9 +
'''ELSE IF''' "*@#" c POS
'''THEN''' LAST 35 +
'''END END END'''
j 2 MOD SWAP DUP DUP + '''IFTE'''
10 / LAST MOD SWAP IP + +
≫ '''NEXT'''
10 SWAP 10 MOD - 10 MOD
SWAP 9 DUP SUB STR→ ==
≫ ''''CUSIP?'''' STO
|
'''BTWEEN''' ''( "char" "from" "to" -- pos )''
evaluate "from" ≤ "char ≤ "to"
if yes, return relative position from "from"
'''CUSIP?''' ''( "CUSIP" -- boolean )''
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...)
v := p + 9
else if c = "*", "@", "#" then
v := 36, 37, 38
if i is even then v := v × 2
sum := sum + int ( v div 10 ) + v mod 10
repeat
get (10 - (sum mod 10)) mod 10
return true if equal to 9th digit
|}
{{in}}
<pre>
≪ { "037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105" } → tests
≪ {} 1 tests SIZE FOR n
tests n GET n CUSIP? "Yes" "No" IFTE + NEXT
≫ ≫ EVAL
</pre>
{{out}}
<pre>
1: { "Yes" "Yes" "Yes" "Yes" "No" "Yes" }
</pre>
</pre>


=={{header|Ruby}}==
=={{header|Ruby}}==
===Following pseudocode===
===Following pseudocode===
<lang ruby>
<syntaxhighlight lang=ruby>
#!/usr/bin/env ruby
#!/usr/bin/env ruby


Line 3,441: Line 4,264:
end
end


</syntaxhighlight>
</lang>


Output:
Output:
Line 3,454: Line 4,277:
===More concise===
===More concise===
Since it uses methods like chain, to_h, sum, and infinite Range syntax (0..), this needs a Ruby version > 2.5
Since it uses methods like chain, to_h, sum, and infinite Range syntax (0..), this needs a Ruby version > 2.5
<lang Ruby>
<syntaxhighlight lang=Ruby>
TABLE = ("0".."9").chain("A".."Z", %w(* @ #)).zip(0..).to_h
TABLE = ("0".."9").chain("A".."Z", %w(* @ #)).zip(0..).to_h


Line 3,466: Line 4,289:
CUSIPs = %w(037833100 17275R102 38259P508 594918104 68389X106 68389X105)
CUSIPs = %w(037833100 17275R102 38259P508 594918104 68389X106 68389X105)
CUSIPs.each{|cusip| puts "#{cusip}: #{valid_CUSIP? cusip}"}
CUSIPs.each{|cusip| puts "#{cusip}: #{valid_CUSIP? cusip}"}
</syntaxhighlight>
</lang>


=={{header|Rust}}==
=={{header|Rust}}==


<lang rust>fn cusip_check(cusip: &str) -> bool {
<syntaxhighlight lang=rust>fn cusip_check(cusip: &str) -> bool {
if cusip.len() != 9 {
if cusip.len() != 9 {
return false;
return false;
Line 3,511: Line 4,334:
println!("{} -> {}", code, cusip_check(code))
println!("{} -> {}", code, cusip_check(code))
}
}
}</lang>
}</syntaxhighlight>


Output:
Output:
Line 3,524: Line 4,347:
=={{header|Scala}}==
=={{header|Scala}}==
{{Out}}See it running in your browser by [https://scalafiddle.io/sf/jwxwWpq/0 ScalaFiddle (JavaScript, non JVM)] or by [https://scastie.scala-lang.org/OBrz9l14Rm2C6tV8tiwhWg Scastie (JVM)].
{{Out}}See it running in your browser by [https://scalafiddle.io/sf/jwxwWpq/0 ScalaFiddle (JavaScript, non JVM)] or by [https://scastie.scala-lang.org/OBrz9l14Rm2C6tV8tiwhWg Scastie (JVM)].
<lang Scala>object Cusip extends App {
<syntaxhighlight lang=Scala>object Cusip extends App {


val candidates = Seq("037833100", "17275R102", "38259P508", "594918104", "68389X106", "68389X105")
val candidates = Seq("037833100", "17275R102", "38259P508", "594918104", "68389X106", "68389X105")
Line 3,539: Line 4,362:
var v = 0
var v = 0
if (c >= '0' && c <= '9') v = c - 48
if (c >= '0' && c <= '9') v = c - 48
else if (c >= 'A' && c <= 'Z') v = c - 64 // lower case letters apparently invalid
else if (c >= 'A' && c <= 'Z') v = c - 55 // lower case letters apparently invalid
else if (c == '*') v = 36
else if (c == '*') v = 36
else if (c == '@') v = 37
else if (c == '@') v = 37
Line 3,551: Line 4,374:
}
}


}</lang>
}</syntaxhighlight>


=={{header|SNOBOL4}}==
=={{header|SNOBOL4}}==
<lang snobol4>#!/usr/local/bin/snobol4 -r
<syntaxhighlight lang=snobol4>#!/usr/local/bin/snobol4 -r
* cusip.sno
* cusip.sno
* -- Committee on Uniform Security Identification Procedures
* -- Committee on Uniform Security Identification Procedures
Line 3,603: Line 4,426:
68389X10
68389X10
68389X1059
68389X1059
68389x105</lang>
68389x105</syntaxhighlight>
{{out}}
{{out}}
<pre>037833100 valid.
<pre>037833100 valid.
Line 3,617: Line 4,440:
=={{header|Swift}}==
=={{header|Swift}}==


<lang swift>struct CUSIP {
<syntaxhighlight lang=swift>struct CUSIP {
var value: String
var value: String


Line 3,683: Line 4,506:
print("Valid")
print("Valid")
}
}
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 3,696: Line 4,519:
=={{header|Tcl}}==
=={{header|Tcl}}==
=== Direct translation of pseudocode ===
=== Direct translation of pseudocode ===
<lang Tcl>proc ordinal-of-alpha {c} { ;# returns ordinal position of c in the alphabet (A=1, B=2...)
<syntaxhighlight lang=Tcl>proc ordinal-of-alpha {c} { ;# returns ordinal position of c in the alphabet (A=1, B=2...)
lsearch {_ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} [string toupper $c]
lsearch {_ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} [string toupper $c]
}
}
Line 3,733: Line 4,556:
set cusip [string range $cusip 0 end-1]
set cusip [string range $cusip 0 end-1]
expr {$last eq [Cusip-Check-Digit $cusip]}
expr {$last eq [Cusip-Check-Digit $cusip]}
}</lang>
}</syntaxhighlight>


=== More idiomatic Tcl ===
=== More idiomatic Tcl ===
<lang Tcl>proc check-cusip {code} {
<syntaxhighlight lang=Tcl>proc check-cusip {code} {
if {[string length $code] != 9} {
if {[string length $code] != 9} {
return false
return false
Line 3,752: Line 4,575:
}
}
expr {$sum % 10 == 0}
expr {$sum % 10 == 0}
}</lang>
}</syntaxhighlight>


=== Common test harness ===
=== Common test harness ===
<lang Tcl>proc test {} {
<syntaxhighlight lang=Tcl>proc test {} {
foreach {cusip name} {
foreach {cusip name} {
037833100 "Apple Incorporated"
037833100 "Apple Incorporated"
Line 3,768: Line 4,591:
}
}
}
}
test</lang>
test</syntaxhighlight>


=== Output ===
=== Output ===
Line 3,779: Line 4,602:
Oracle Corporation valid</pre>
Oracle Corporation valid</pre>


=={{header|VBA}}==
=={{header|V (Vlang)}}==
{{trans|Go}}
<lang vb>Private Function Cusip_Check_Digit(s As Variant) As Integer
<syntaxhighlight lang="v (vlang)">fn is_cusip(s string) bool {
Dim Sum As Integer, c As String, v As Integer
For i = 1 To 8
if s.len != 9 { return false }
c = Mid(s, i, 1)
mut sum := 0
If IsNumeric(c) Then
for i in 0..8 {
v = Val(c)
c := s[i]
Else
mut v :=0
Select Case c
match true {
Case "a" To "z"
c >= '0'[0] && c <= '9'[0] {
v = Asc(c) - Asc("a") + 10
v = c - 48
}
Case "A" To "Z"
v = Asc(c) - Asc("A") + 10
c >= 'A'[0] && c <= 'Z'[0] {
Case "*"
v = c - 55
}
v = 36
Case "@"
c == '*'[0] {
v = 37
Case "#"
v = 38
Case Else
Debug.Print "not expected"
End Select
End If
If i Mod 2 = 0 Then v = v * 2
Sum = Sum + Int(v \ 10) + v Mod 10
Next i
Cusip_Check_Digit = (10 - (Sum Mod 10)) Mod 10
End Function</lang>{{out}}
<pre>037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 not valid
68389X105 is valid</pre>

=={{header|Visual Basic .NET}}==
{{trans|C#}}
<lang vbnet>Module Module1

Function IsCUSIP(s As String) As Boolean
If s.Length <> 9 Then
Return False
End If

Dim sum = 0
For i = 0 To 7
Dim c = s(i)

Dim v As Integer
If "0" <= c AndAlso c <= "9" Then
v = Asc(c) - 48
ElseIf "A" <= c AndAlso c <= "Z" Then
v = Asc(c) - 64 ' Lower case letters are apparently invalid
ElseIf c = "*" Then
v = 36
v = 36
}
ElseIf c = "#" Then
c == '@'[0] {
v = 37
}
c == '#'[0] {
v = 38
v = 38
}
Else
Return False
else {
End If
return false
}

If i Mod 2 = 1 Then
v *= 2 ' check if odd as using 0-based indexing
End If
sum += v \ 10 + v Mod 10
Next
Return Asc(s(8)) - 48 = (10 - (sum Mod 10)) Mod 10
End Function

Sub Main()
Dim candidates As New List(Of String) From {
"037833100",
"17275R102",
"38259P508",
"594918104",
"68389X106",
"68389X105"
}
}
if i % 2 == 1 { v *= 2 } // check if odd as using 0-based indexing
sum += v/10 + v%10
}
return int(s[8]) - 48 == (10 - (sum%10)) % 10
}
fn main() {
candidates := [
"037833100",
"17275R102",
"38259P508",
"594918104",
"68389X106",
"68389X105",
]
for candidate in candidates {
mut b :=' '
if is_cusip(candidate) {
b = "correct"
} else {
b = "incorrect"
}
println("$candidate -> $b")
}
}</syntaxhighlight>


For Each candidate In candidates
Console.WriteLine("{0} -> {1}", candidate, If(IsCUSIP(candidate), "correct", "incorrect"))
Next
End Sub

End Module</lang>
{{out}}
{{out}}
<pre>
<pre>037833100 -> correct
037833100 -> correct
17275R102 -> correct
17275R102 -> correct
38259P508 -> correct
38259P508 -> correct
594918104 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X106 -> incorrect
68389X105 -> correct</pre>
68389X105 -> correct
</pre>


=={{header|Wren}}==
=={{header|Wren}}==
{{trans|Go}}
{{trans|Go}}
<lang ecmascript>var isCusip = Fn.new { |s|
<syntaxhighlight lang="wren">var isCusip = Fn.new { |s|
if (s.count != 9) return false
if (s.count != 9) return false
var sum = 0
var sum = 0
Line 3,883: Line 4,678:
v = c - 48
v = c - 48
} else if (c >= 65 && c <= 90) { // 'A' to 'Z'
} else if (c >= 65 && c <= 90) { // 'A' to 'Z'
v = c - 64
v = c - 55
} else if (s[i] == "*") {
} else if (s[i] == "*") {
v = 36
v = 36
Line 3,910: Line 4,705:
var b = (isCusip.call(candidate)) ? "correct" : "incorrect"
var b = (isCusip.call(candidate)) ? "correct" : "incorrect"
System.print("%(candidate) -> %(b)")
System.print("%(candidate) -> %(b)")
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 3,923: Line 4,718:


=={{header|XPL0}}==
=={{header|XPL0}}==
<lang XPL0>string 0; \use zero-terminated strings
<syntaxhighlight lang=XPL0>string 0; \use zero-terminated strings


func Valid(Cusip); \Return 'true' if valid CUSIP code
func Valid(Cusip); \Return 'true' if valid CUSIP code
Line 3,961: Line 4,756:
CrLf(0);
CrLf(0);
];
];
]</lang>
]</syntaxhighlight>


{{out}}
{{out}}
Line 3,973: Line 4,768:
</pre>
</pre>


=={{header|Yabasic}}==
=={{header|Zig}}==
<syntaxhighlight lang=zig>const std = @import("std");
{{trans|FreeBASIC}}
const print = std.debug.print;
<lang Yabasic>sub cusip(inputStr$)

local i, v, sum, x$
pub fn CusipCheckDigit(cusip: *const [9:0]u8) bool {
Print inputStr$;
var i: usize = 0;
var sum: i32 = 0;
If Len(inputStr$) <> 9 Print " length is incorrect, invalid cusip" : return
while (i < 8) {
For i = 1 To 8
const c = cusip[i];
x$ = mid$(inputStr$, i, 1)
var v: i32 = undefined;
switch x$
if (c <= '9' and c >= '0') {
Case "*": v = 36 : break
v = c - 48;
Case "@": v = 37 : break
}
Case "#": v = 38 : break
else if (c <= 'Z' and c >= 'A') {
default:
v = c - 55;
}
if x$ >= "A" and x$ <= "Z" then
v = asc(x$) - Asc("A") + 10
else if (c == '*') {
elsif x$ >= "0" and x$ <= "9" then
v = 36;
}
v = asc(x$) - asc("0")
else
else if (c == '@') {
v = 37;
Print " found a invalid character, invalid cusip"
return
}
end if
else if (c == '#') {
End switch
v = 38;
}
If and(i, 1) = 0 v = v * 2
else {
sum = sum + int(v / 10) + mod(v, 10)
return false;
Next
}
if (i % 2 == 1) {
sum = mod(10 - mod(sum, 10), 10)
v *= 2;
}
If sum = asc(mid$(inputStr$, 9, 1)) - Asc("0") Then
Print " is valid"
sum = sum + @divFloor(v, 10) + @mod(v, 10);
Else
i += 1;
}
Print " is invalid"
return (cusip[8] - 48 == @mod((10 - @mod(sum, 10)), 10));
End If
}

End Sub
pub fn main() void {
const cusips = [_]*const [9:0]u8 {
// ------=< MAIN >=------
"037833100",
Data "037833100", "17275R102", "38259P508"
"17275R102",
"38259P508",
Data "594918104", "68389X106", "68389X105", ""
"594918104",
"68389X106",
Print
"68389X105"
do
Read inputStr$
};
if inputStr$ = "" break
for (cusips) |cusip| {
print("{s} -> {}\n", .{cusip, CusipCheckDigit(cusip)});
cusip(inputStr$)
}
loop
}
</lang>
</syntaxhighlight>


=={{header|zkl}}==
=={{header|zkl}}==
<lang zkl>fcn cusipCheckDigit(cusip){
<syntaxhighlight lang=zkl>fcn cusipCheckDigit(cusip){
var [const] vs=[0..9].chain(["A".."Z"],T("*","@","#")).pump(String);
var [const] vs=[0..9].chain(["A".."Z"],T("*","@","#")).pump(String);
try{
try{
Line 4,032: Line 4,828:
((10 - sum%10)%10 == cusip[8].toInt()) and cusip.len()==9
((10 - sum%10)%10 == cusip[8].toInt()) and cusip.len()==9
}catch{ False }
}catch{ False }
}</lang>
}</syntaxhighlight>
<lang zkl>foreach cusip in (T("037833100", "17275R102",
<syntaxhighlight lang=zkl>foreach cusip in (T("037833100", "17275R102",
"38259P508", "594918104", "68389X106", "68389X105")){
"38259P508", "594918104", "68389X106", "68389X105")){
println(cusip,": ",cusipCheckDigit(cusip));
println(cusip,": ",cusipCheckDigit(cusip));
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>

Latest revision as of 23:00, 12 April 2024

Task
CUSIP
You are encouraged to solve this task according to the task description, using any language you may know.
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


11l

Translation of: Python
F cusip_check(=cusip)
   I cusip.len != 9
      X.throw ValueError(‘CUSIP must be 9 characters’)

   cusip = cusip.uppercase()
   V total = 0
   L(i) 8
      V v = 0
      V c = cusip[i]
      I c.is_digit()
         v = Int(c)
      E I c.is_alpha()
         V p = c.code - ‘A’.code + 1
         v = p + 9
      E I c == ‘*’
         v = 36
      E I c == ‘@’
         v = 37
      E I c == ‘#’
         v = 38

      I i % 2 != 0
         v *= 2

      total += v I/ 10 + v % 10
   V check = (10 - (total % 10)) % 10
   R String(check) == cusip.last

V codes = [‘037833100’,
           ‘17275R102’,
           ‘38259P508’,
           ‘594918104’,
           ‘68389X106’,
           ‘68389X105’]
L(code) codes
   print(code‘: ’(I cusip_check(code) {‘valid’} E ‘invalid’))
Output:
037833100: valid
17275R102: valid
38259P508: valid
594918104: valid
68389X106: invalid
68389X105: valid

360 Assembly

*        CUSIP                     07/06/2018
CUSIP    CSECT
         USING  CUSIP,R13          base register
         B      72(R15)            skip savearea
         DC     17F'0'             savearea
         SAVE   (14,12)            save previous context
         ST     R13,4(R15)         link backward
         ST     R15,8(R13)         link forward
         LR     R13,R15            set addressability
         LA     R6,1               i=1
       DO WHILE=(C,R6,LE,=F'6')    do i=1 to 6
         LR     R1,R6                i
         MH     R1,=H'9'             *9
         LA     R4,T-9(R1)           @t(i)
         MVC    X,0(R4)              x=t(i)
         SR     R10,R10              w=0
         LA     R7,1                 j=1
       DO WHILE=(C,R7,LE,=F'8')      do j=1 to 8
         LA     R14,X-1                x
         AR     R14,R7                 j
         MVC    Y(1),0(R14)            y=substr(x,j,1)
         LA     R9,L'XX                z=length(xx)
         LA     R8,1                   k=1
       DO WHILE=(C,R8,LE,=A(L'XX))     do k=1 to length(xx)
         LA     R4,XX-1                  xx
         AR     R4,R8                    k
         MVC    C(1),0(R4)               c=substr(xx,k,1)
       IF CLC,Y(1),EQ,C THEN             if y=c then
         LR     R9,R8                      k
         BCTR   R9,0                       z=k-1
       ENDIF    ,                        endif
         LA     R8,1(R8)                 k++
       ENDDO    ,                      enddo k
         LR     R4,R7                  j
         LA     R1,2                   2
         SRDA   R4,32                  ~
         DR     R4,R1                  j/2=0
       IF LTR,R4,Z,R4 THEN             if j//2=0 then
         AR     R9,R9                    z=z+z
       ENDIF    ,                      endif
         LR     R4,R9                  z
         LA     R1,10                  10
         SRDA   R4,32                  ~
         DR     R4,R1                  r4=z//10 ; r5=z/10
         AR     R10,R5                 w+z/10
         AR     R10,R4                 w=w+z/10+z//10
         LA     R7,1(R7)               j++
       ENDDO    ,                    enddo j
         LR     R4,R10               w
         LA     R1,10                10
         SRDA   R4,32                ~
         DR     R4,R1                w/10
         LA     R2,10                10
         SR     R2,R4                10-w//10
         SRDA   R2,32                ~
         DR     R2,R1                /10
         STC    R2,U                 u=(10-w//10)//10
         OI     U,X'F0'              bin to char
       IF CLC,U,EQ,X+8 THEN          if u=substr(x,9,1) then
         MVC    OK,=CL3' '             ok=' '
       ELSE     ,                    else
         MVC    OK,=C'n''t'            ok='n''t'
       ENDIF    ,                    endif
         MVC    PG+6(9),X            output x
         MVC    PG+18(3),OK          output ok
         XPRNT  PG,L'PG              print
         LA     R6,1(R6)             i++
       ENDDO    ,                  enddo i
         L      R13,4(0,R13)       restore previous savearea pointer
         RETURN (14,12),RC=0       restore registers from calling sav
XX       DC     CL39'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#'
U        DS     CL1
Y        DS     CL1
C        DS     CL1
T        DC     CL9'037833100',CL9'17275R102',CL9'38259P508'
         DC     CL9'594918104',CL9'68389X106',CL9'68389X105'
X        DS     CL9
OK       DS     CL3
PG       DC     CL80'CUSIP ......... is... valid'
         YREGS
         END    CUSIP
Output:
CUSIP 037833100 is    valid
CUSIP 17275R102 is    valid
CUSIP 38259P508 is    valid
CUSIP 594918104 is    valid
CUSIP 68389X106 isn't valid
CUSIP 68389X105 is    valid

Action!

INCLUDE "D2:CHARTEST.ACT" ;from the Action! Tool Kit

BYTE FUNC Verify(CHAR ARRAY code)
  BYTE i,c,v
  CARD sum

  IF code(0)#9 THEN
    RETURN (0)
  ELSEIF IsDigit(code(1))=0 THEN
    RETURN (0)
  FI

  sum=0
  FOR i=2 TO code(0)
  DO
    c=code(i)
    IF IsDigit(c) THEN
      v=c-'0
    ELSEIF IsAlpha(c) THEN
      v=ToUpper(c)-'A+10
    ELSEIF c='* THEN
      v=36
    ELSEIF c='@ THEN
      v=37
    ELSEIF c='# THEN
      v=38
    ELSE
      RETURN (0)
    FI

    IF (i&1)=0 THEN
      v==*2
    FI

    sum==+v/10+v MOD 10
  OD

  v=(10-(sum MOD 10)) MOD 10
  IF v#code(1)-'0 THEN
    RETURN (0)
  FI
RETURN (1)

PROC Test(CHAR ARRAY code)
  Print(code)
  IF Verify(code) THEN
    PrintE(" is valid")
  ELSE
    PrintE(" is invalid")
  FI
RETURN

PROC Main()
  Put(125) PutE() ;clear the screen
  Test("037833100")
  Test("17275R102")
  Test("38259P508")
  Test("594918104")
  Test("68389X106")
  Test("68389X105")
RETURN
Output:

Screenshot from Atari 8-bit computer

037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
68389X105 is valid

Ada

with Ada.Text_IO;

procedure Cusip_Test is
   use Ada.Text_IO;

   subtype Cusip is String (1 .. 9);

   function Check_Cusip (Code : Cusip) return Boolean is
      Sum : Integer := 0;
      V   : Integer;

   begin
      for I in Code'First .. Code'Last - 1 loop
         case Code (I) is
            when '0' .. '9' =>
               V := Character'Pos (Code (I)) - Character'Pos ('0');
            when 'A' .. 'Z' =>
               V := Character'Pos (Code (I)) - Character'Pos ('A') + 10;
            when '*' => V := 36;
            when '@' => V := 37;
            when '#' => V := 38;
            when others => return False;
         end case;

         if I mod 2 = 0 then
            V := V * 2;
         end if;

         Sum := Sum + V / 10 + (V mod 10);
      end loop;

      return (10 - (Sum mod 10)) mod 10 =
        Character'Pos (Code (Code'Last)) - Character'Pos ('0');
   end Check_Cusip;

   type Cusip_Array is array (Natural range <>) of Cusip;

   Test_Array : Cusip_Array :=
     ("037833100",
      "17275R102",
      "38259P508",
      "594918104",
      "68389X106",
      "68389X105");
begin
   for I in Test_Array'Range loop
      Put (Test_Array (I) & ": ");
      if Check_Cusip (Test_Array (I)) then
         Put_Line ("valid");
      else
         Put_Line ("not valid");
      end if;
   end loop;
end Cusip_Test;
Output:
037833100: valid
17275R102: valid
38259P508: valid
594918104: valid
68389X106: not valid
68389X105: valid

ALGOL 68

BEGIN
    # returns TRUE if cusip is a valid CUSIP code #
    OP ISCUSIP = ( STRING cusip )BOOL:
       IF ( UPB cusip - LWB cusip ) /= 8
       THEN
           # code is wrong length #
           FALSE
       ELSE
           # string is 9 characters long - check it is valid #
           STRING cusip digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#"[ AT 0 ];
           INT check digit := 0;
           IF NOT char in string( cusip[ UPB cusip ], check digit, cusip digits )
           THEN
               # invalid check digit #
               FALSE
           ELSE
               # OK so far compare the calculated check sum to the supplied one #
               INT sum := 0;
               INT c pos := LWB cusip - 1;
               FOR i TO 8 DO
                   INT digit := 0;
                   IF NOT char in string( cusip[ i + c pos ], digit, cusip digits )
                   THEN
                       # invalid digit #
                       digit := -999
                   FI;
                   IF NOT ODD i
                   THEN
                       # even digit #
                       digit *:= 2
                   FI;
                   sum +:= ( digit OVER 10 ) + ( digit MOD 10 )
               OD;
               ( 10 - ( sum MOD 10 ) ) MOD 10 = check digit
           FI
       FI ; # ISCUSIP #

    # task test cases #

    PROC test cusip = ( STRING cusip )VOID:
        print( ( cusip, IF ISCUSIP cusip THEN " valid" ELSE " invalid" FI, newline ) );

    test cusip( "037833100" );
    test cusip( "17275R102" );
    test cusip( "38259P508" );
    test cusip( "594918104" );
    test cusip( "68389X106" );
    test cusip( "68389X105" )
END
Output:
037833100 valid
17275R102 valid
38259P508 valid
594918104 valid
68389X106 invalid
68389X105 valid

ALGOL W

Based on Algol 68

begin    % returns true if cusip is a valid CUSIP code %
    logical procedure isCusip ( string(9) value cusip ) ;
    begin
        % returns the base 39 digit corresponding to a character of a CUSIP code %
        integer procedure cusipDigit( string(1) value cChar ) ;
            if      cChar >= "0" and cChar <= "9" then ( decode( cChar ) - decode( "0" ) )
            else if cChar >= "A" and cChar <= "Z" then ( decode( cChar ) - decode( "A" ) ) + 10
            else if cChar  = "*"                  then   36
            else if cChar  = "@"                  then   37
            else if cChar  = "#"                  then   38
            else    % invalid digit %                  -999 ;

        integer checkDigit, sum;
        checkDigit := cusipDigit( cusip( 8 // 1 ) );
        for cPos := 1 until 8 do begin
            integer   digit;
            digit := cusipDigit( cusip( ( cPos - 1 ) // 1 ) );
            if not odd( cPos ) then digit := digit * 2;
            sum := sum + ( digit div 10 ) + ( digit rem 10 )
        end for_cPos ;
        ( ( 10 - ( sum rem 10 ) ) rem 10 ) = checkDigit
    end isCusip ;

    begin % task test cases %
        procedure testCusip ( string(9) value cusip ) ;
            write( s_w := 0, cusip, if isCusip( cusip ) then " valid" else " invalid" );

        testCusip( "037833100" );
        testCusip( "17275R102" );
        testCusip( "38259P508" );
        testCusip( "594918104" );
        testCusip( "68389X106" );
        testCusip( "68389X105" )
    end testCases
end.
Output:
037833100 valid
17275R102 valid
38259P508 valid
594918104 valid
68389X106 invalid
68389X105 valid

AppleScript

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions


-- isCusip :: String -> Bool
on isCusip(s)
    set cs to "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*&#"
    set ns to mapMaybe(elemIndex(cs), s)
    
    script go
        on |λ|(f, x)
            set fx to apply(f, x)
            (fx div 10) + (fx mod 10)
        end |λ|
    end script
    
    9 = length of ns and item -1 of ns = (10 - (sum(zipWith(go, ¬
        cycle({my identity, my double}), ¬
        take(8, ns))) mod 10)) mod 10
end isCusip


-------------------------- TEST ---------------------------
on run
    script test
        on |λ|(s)
            s & " -> " & isCusip(s)
        end |λ|
    end script
    
    unlines(map(test, ¬
        {"037833100", "17275R102", "38259P508", ¬
            "594918104", "68389X106", "68389X105"}))
end run

-- 037833100 -> true
-- 17275R102 -> true
-- 38259P508 -> true
-- 594918104 -> true
-- 68389X106 -> false
-- 68389X105 -> true


-------------------- GENERIC FUNCTIONS --------------------

-- Just :: a -> Maybe a
on Just(x)
    -- Constructor for an inhabited Maybe (option type) value.
    -- Wrapper containing the result of a computation.
    {type:"Maybe", Nothing:false, Just:x}
end Just


-- Nothing :: Maybe a
on Nothing()
    -- Constructor for an empty Maybe (option type) value.
    -- Empty wrapper returned where a computation is not possible.
    {type:"Maybe", Nothing:true}
end Nothing


-- Tuple (,) :: a -> b -> (a, b)
on Tuple(a, b)
    -- Constructor for a pair of values, possibly of two different types.
    {type:"Tuple", |1|:a, |2|:b, length:2}
end Tuple


-- apply ($) :: (a -> b) -> a -> b
on apply(f, x)
    -- The value of f(x)
    mReturn(f)'s |λ|(x)
end apply


-- cycle :: [a] -> Generator [a]
on cycle(xs)
    script
        property lng : 1 + (length of xs)
        property i : missing value
        on |λ|()
            if missing value is i then
                set i to 1
            else
                set nxt to (1 + i) mod lng
                if 0 = ((1 + i) mod lng) then
                    set i to 1
                else
                    set i to nxt
                end if
            end if
            return item i of xs
        end |λ|
    end script
end cycle


-- double :: Num -> Num
on double(x)
    2 * x
end double


-- elemIndex :: Eq a => [a] -> a -> Maybe Int
on elemIndex(xs)
    script
        on |λ|(x)
            set lng to length of xs
            repeat with i from 1 to lng
                if x = (item i of xs) then return Just(i - 1)
            end repeat
            return Nothing()
        end |λ|
    end script
end elemIndex


-- identity :: a -> a
on identity(x)
    -- The argument unchanged.
    x
end identity


-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl


-- length :: [a] -> Int
on |length|(xs)
    set c to class of xs
    if list is c or string is c then
        length of xs
    else
        (2 ^ 29 - 1) -- (maxInt - simple proxy for non-finite)
    end if
end |length|


-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    -- The list obtained by applying f
    -- to each element of xs.
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map


-- The mapMaybe function is a version of map which can throw out
-- elements. In particular, the functional argument returns
-- something of type Maybe b. If this is Nothing, no element is
-- added on to the result list. If it just Just b, then b is
-- included in the result list.
-- mapMaybe :: (a -> Maybe b) -> [a] -> [b]
on mapMaybe(mf, xs)
    script
        property g : mReturn(mf)
        on |λ|(a, x)
            set mb to g's |λ|(x)
            if Nothing of mb then
                a
            else
                a & (Just of mb)
            end if
        end |λ|
    end script
    foldl(result, {}, xs)
end mapMaybe


-- min :: Ord a => a -> a -> a
on min(x, y)
    if y < x then
        y
    else
        x
    end if
end min


-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    -- 2nd class handler function lifted into 1st class script wrapper. 
    if script is class of f then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn


-- sum :: [Num] -> Num
on sum(xs)
    script add
        on |λ|(a, b)
            a + b
        end |λ|
    end script
    
    foldl(add, 0, xs)
end sum


-- take :: Int -> [a] -> [a]
-- take :: Int -> String -> String
on take(n, xs)
    set c to class of xs
    if list is c then
        if 0 < n then
            items 1 thru min(n, length of xs) of xs
        else
            {}
        end if
    else if string is c then
        if 0 < n then
            text 1 thru min(n, length of xs) of xs
        else
            ""
        end if
    else if script is c then
        set ys to {}
        repeat with i from 1 to n
            set v to |λ|() of xs
            if missing value is v then
                return ys
            else
                set end of ys to v
            end if
        end repeat
        return ys
    else
        missing value
    end if
end take


-- unlines :: [String] -> String
on unlines(xs)
    -- A single string formed by the intercalation
    -- of a list of strings with the newline character.
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, linefeed}
    set str to xs as text
    set my text item delimiters to dlm
    str
end unlines


-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
on zipWith(f, xs, ys)
    set lng to min(|length|(xs), |length|(ys))
    if 1 > lng then return {}
    set xs_ to take(lng, xs) -- Allow for non-finite
    set ys_ to take(lng, ys) -- generators like cycle etc
    set lst to {}
    tell mReturn(f)
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs_, item i of ys_)
        end repeat
        return lst
    end tell
end zipWith
Output:
037833100 -> true
17275R102 -> true
38259P508 -> true
594918104 -> true
68389X106 -> false
68389X105 -> true

Arturo

Translation of: Ruby
validCUSIP?: function [cusip][
    s: 0
    alpha: `A`..`Z`

    loop.with:'i chop cusip 'c [
        v: 0

        case ø
            when? [numeric? c] -> v: to :integer to :string c
            when? [in? c alpha] -> v: (index alpha c) + 1 + 9
            when? [c = `*`] -> v: 36
            when? [c = `@`] -> v: 37
            when? [c = `#`] -> v: 38
            else []

        if odd? i -> v: 2 * v

        s: s + (v / 10) + (v % 10)
    ]
    check: (10 - (s % 10)) % 10

    return check = to :integer to :string last cusip
]

loop ["037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105"] 'cusip [
    print [cusip "=>" (validCUSIP? cusip)? -> "VALID" -> "INVALID"]
]
Output:
037833100 => VALID 
17275R102 => VALID 
38259P508 => VALID 
594918104 => VALID 
68389X106 => INVALID 
68389X105 => VALID

AutoHotkey

Cusip_Check_Digit(cusip){
    sum := 0, i := 1, x := StrSplit(cusip)
    while (i <= 8) {
        c := x[i]
        if c is digit
            v := c
        else if c is alpha
            v := Asc(c) - 64 + 9
        else if (c = "*")
            v := 36
        else if (c = "@")
            v := 37
        else if (c = "#")
            v := 38
        if (i/2 = Floor(i/2))
            v *= 2
        sum += Floor(v/10) + Mod(v, 10)
        i++
    }
    return (Mod(10 - Mod(sum, 10), 10) = x[9])
}

Examples:

data =
(
037833100
17275R102
38259P508
594918104
68389X106
68389X105
)

output := "Cusip`t`tValid`n"
loop, Parse, data, `n, `r
    output .= A_LoopField "`t" Cusip_Check_Digit(A_LoopField) "`n"
MsgBox % output
Output:
Cusip		Valid
037833100	1
17275R102	1
38259P508	1
594918104	1
68389X106	0
68389X105	1

AWK

# syntax: GAWK -f CUSIP.AWK
BEGIN {
    n = split("037833100,17275R102,38259P508,594918104,68389X106,68389X105",arr,",")
    for (i=1; i<=n; i++) {
      printf("%9s %s\n",arr[i],cusip(arr[i]))
    }
    exit(0)
}
function cusip(n,  c,i,sum,v,x) {
# returns: 1=OK, 0=NG, -1=bad data
    if (length(n) != 9) {
      return(-1)
    }
    for (i=1; i<=8; i++) {
      c = substr(n,i,1)
      if (c ~ /[0-9]/) {
        v = c
      }
      else if (c ~ /[A-Z]/) {
        v = index("ABCDEFGHIJKLMNOPQRSTUVWXYZ",c) + 9
      }
      else if (c == "*") {
        v = 36
      }
      else if (c == "@") {
        v = 37
      }
      else if (c == "#") {
        v = 38
      }
      else {
        return(-1)
      }
      if (i ~ /[02468]/) {
        v *= 2
      }
      sum += int(v / 10) + (v % 10)
    }
    x = (10 - (sum % 10)) % 10
    return(substr(n,9,1) == x ? 1 : 0)
}
Output:
037833100 1
17275R102 1
38259P508 1
594918104 1
68389X106 0
68389X105 1

BASIC

FreeBASIC

' version 04-04-2017
' compile with: fbc -s console

sub cusip(input_str As String)

    Print input_str;
    If Len(input_str) <> 9 Then
        Print " length is incorrect, invalid cusip"
        Return
    End If

    Dim As Long i, v , sum
    Dim As UByte x

    For i = 1 To 8
        x = input_str[i-1]
        Select Case x
            Case Asc("0") To Asc("9")
                v = x - Asc("0")
            Case Asc("A") To Asc("Z")
                v = x - Asc("A") + 1 + 9
            Case Asc("*")
                v= 36
            Case Asc("@")
                v = 37
            Case Asc("#")
                v = 38
            Case Else
                Print " found a invalid character, invalid cusip"
                return
        End Select

        If (i And 1) = 0 Then v = v * 2
        sum = sum + v \ 10 + v Mod 10
    Next

    sum = (10 - (sum Mod 10)) Mod 10
    If sum = (input_str[8] - Asc("0")) Then
        Print " is valid"
    Else
        Print " is invalid"
    End If

End Sub

' ------=< MAIN >=------

Data "037833100", "17275R102", "38259P508"
Data "594918104", "68389X106", "68389X105"

Dim As String input_str

Print
For i As Integer = 1 To 6
    Read input_str
    cusip(input_str)
Next

' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End
Output:
037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
68389X105 is valid

VBA

Private Function Cusip_Check_Digit(s As Variant) As Integer
    Dim Sum As Integer, c As String, v As Integer
    For i = 1 To 8
        c = Mid(s, i, 1)
        If IsNumeric(c) Then
            v = Val(c)
        Else
            Select Case c
                Case "a" To "z"
                    v = Asc(c) - Asc("a") + 10
                Case "A" To "Z"
                    v = Asc(c) - Asc("A") + 10
                Case "*"
                    v = 36
                Case "@"
                    v = 37
                Case "#"
                    v = 38
                Case Else
                    Debug.Print "not expected"
            End Select
        End If
        If i Mod 2 = 0 Then v = v * 2
        Sum = Sum + Int(v \ 10) + v Mod 10
    Next i
    Cusip_Check_Digit = (10 - (Sum Mod 10)) Mod 10
End Function
Output:
037833100     is valid
17275R102     is valid
38259P508     is valid
594918104     is valid
68389X106     not valid
68389X105     is valid

Visual Basic .NET

Translation of: C#
Module Module1

    Function IsCUSIP(s As String) As Boolean
        If s.Length <> 9 Then
            Return False
        End If

        Dim sum = 0
        For i = 0 To 7
            Dim c = s(i)

            Dim v As Integer
            If "0" <= c AndAlso c <= "9" Then
                v = Asc(c) - 48
            ElseIf "A" <= c AndAlso c <= "Z" Then
                v = Asc(c) - 55 ' Lower case letters are apparently invalid
            ElseIf c = "*" Then
                v = 36
            ElseIf c = "#" Then
                v = 38
            Else
                Return False
            End If

            If i Mod 2 = 1 Then
                v *= 2 ' check if odd as using 0-based indexing
            End If
            sum += v \ 10 + v Mod 10
        Next
        Return Asc(s(8)) - 48 = (10 - (sum Mod 10)) Mod 10
    End Function

    Sub Main()
        Dim candidates As New List(Of String) From {
            "037833100",
            "17275R102",
            "38259P508",
            "594918104",
            "68389X106",
            "68389X105"
        }

        For Each candidate In candidates
            Console.WriteLine("{0} -> {1}", candidate, If(IsCUSIP(candidate), "correct", "incorrect"))
        Next
    End Sub

End Module
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

Yabasic

Translation of: FreeBASIC
sub cusip(inputStr$)
    local i, v, sum, x$
 
    Print inputStr$;
    If Len(inputStr$) <> 9 Print " length is incorrect, invalid cusip" : return
 
    For i = 1 To 8
        x$ = mid$(inputStr$, i, 1)
        switch x$
            Case "*": v = 36 : break
            Case "@": v = 37 : break
            Case "#": v = 38 : break
            default:
                if x$ >= "A" and x$ <= "Z" then
                    v = asc(x$) - Asc("A") + 10
                elsif x$ >= "0" and x$ <= "9" then
                    v = asc(x$) - asc("0")
                else
                    Print " found a invalid character, invalid cusip"
                    return
                end if
        End switch
 
        If and(i, 1) = 0 v = v * 2
        sum = sum + int(v / 10) + mod(v, 10)
    Next
 
    sum = mod(10 - mod(sum, 10), 10)
    If sum = asc(mid$(inputStr$, 9, 1)) - Asc("0") Then
        Print " is valid"
    Else
        Print " is invalid"
    End If
 
End Sub
 
// ------=< MAIN >=------
 
Data "037833100", "17275R102", "38259P508"
Data "594918104", "68389X106", "68389X105", ""
 
Print
do
    Read inputStr$
    if inputStr$ = "" break
    cusip(inputStr$)
loop

BCPL

get "libhdr"

let validcusip(c) = valof
$(  let sum = 0
    unless c%0 = 9 resultis false 
    for i = 1 to 8 do
    $(  let v = ( 2 - (i & 1) ) * valof
        $(  test '0' <= c%i <= '9'
                then resultis c%i - '0'
            or test 'A' <= c%i <= 'Z'
                then resultis 10 + c%i - 'A'
            or test c%i = '**'
                then resultis 36
            or test c%i = '@'
                then resultis 37
            or test c%i = '#'
                then resultis 38
            else resultis -1
        $)
        sum := sum + v/10 + v rem 10
    $)
    resultis (10 - (sum rem 10)) rem 10 = c%9 - '0'
$)

let show(c) be
    writef("%S: %Svalid*N", c, validcusip(c) -> "", "in")
    
let start() be
$(  show("037833100")
    show("17275R102")
    show("38259P508")
    show("594918104")
    show("68389X106")
    show("68389X105")
$)
Output:
037833100: valid
17275R102: valid
38259P508: valid
594918104: valid
68389X106: invalid
68389X105: valid

C

Reads CUSIP strings from a file and prints results to console, usage printed on incorrect invocation.

#include<stdlib.h>
#include<stdio.h>

int cusipCheck(char str[10]){
	int sum=0,i,v;
	
	for(i=0;i<8;i++){
		if(str[i]>='0'&&str[i]<='9')
			v = str[i]-'0';
		else if(str[i]>='A'&&str[i]<='Z')
			v = (str[i] - 'A' + 10);
		else if(str[i]=='*')
			v = 36;
		else if(str[i]=='@')
			v = 37;
		else if(str[i]=='#')
			v = 38;
		if(i%2!=0)
			v*=2;
		
		sum += ((int)(v/10) + v%10);
	}
	return ((10 - (sum%10))%10);
}

int main(int argC,char* argV[])
{
	char cusipStr[10];
	
	int i,numLines;
	
	if(argC==1)
		printf("Usage : %s <full path of CUSIP Data file>",argV[0]);
	
	else{
		FILE* fp = fopen(argV[1],"r");
	
		fscanf(fp,"%d",&numLines);
		
		printf("CUSIP       Verdict\n");
		printf("-------------------");
		
		for(i=0;i<numLines;i++){
		
			fscanf(fp,"%s",cusipStr);
		
			printf("\n%s : %s",cusipStr,(cusipCheck(cusipStr)==(cusipStr[8]-'0'))?"Valid":"Invalid");
		}
	
		fclose(fp);
	}
	return 0;
}

Input file :

6
037833100
17275R102
38259P508
594918104
68389X106
68389X105

Invocation and output :

C:\rosettaCode>cusipCheck.exe cusipData.txt
CUSIP       Verdict
-------------------
037833100 : Valid
17275R102 : Valid
38259P508 : Valid
594918104 : Valid
68389X106 : Invalid
68389X105 : Valid

C#

Translation of: Java
using System;
using System.Collections.Generic;

namespace CUSIP {
    class Program {
        static bool IsCusip(string s) {
            if (s.Length != 9) return false;
            int sum = 0;
            for (int i = 0; i <= 7; i++) {
                char c = s[i];

                int v;
                if (c >= '0' && c <= '9') {
                    v = c - 48;
                }
                else if (c >= 'A' && c <= 'Z') {
                    v = c - 55;  // lower case letters apparently invalid
                }
                else if (c == '*') {
                    v = 36;
                }
                else if (c == '#') {
                    v = 38;
                }
                else {
                    return false;
                }
                if (i % 2 == 1) v *= 2;  // check if odd as using 0-based indexing
                sum += v / 10 + v % 10;
            }
            return s[8] - 48 == (10 - (sum % 10)) % 10;
        }

        static void Main(string[] args) {
            List<string> candidates = new List<string>() {
                "037833100",
                "17275R102",
                "38259P508",
                "594918104",
                "68389X106",
                "68389X105"
            };
            foreach (var candidate in candidates) {
                Console.WriteLine("{0} -> {1}", candidate, IsCusip(candidate) ? "correct" : "incorrect");
            }
        }
    }
}
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

C++

Translation of: C#
#include <iostream>
#include <vector>

bool isCusip(const std::string& s) {
    if (s.size() != 9) return false;

    int sum = 0;
    for (int i = 0; i <= 7; ++i) {
        char c = s[i];

        int v;
        if ('0' <= c && c <= '9') {
            v = c - '0';
        } else if ('A' <= c && c <= 'Z') {
            v = c - 'A' + 10;
        } else if (c = '*') {
            v = 36;
        } else if (c = '@') {
            v = 37;
        } else if (c = '#') {
            v = 38;
        } else {
            return false;
        }
        if (i % 2 == 1) {
            v *= 2;
        }
        sum += v / 10 + v % 10;
    }
    return s[8] - '0' == (10 - (sum % 10)) % 10;
}

int main() {
    using namespace std;

    vector<string> candidates{
        "037833100",
        "17275R102",
        "38259P508",
        "594918104",
        "68389X106",
        "68389X105"
    };

    for (auto str : candidates) {
        auto res = isCusip(str) ? "correct" : "incorrect";
        cout << str.c_str() << " -> " << res << "\n";
    }

    return 0;
}
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

Caché ObjectScript

Class Utils.Check [ Abstract ]
{

ClassMethod CUSIP(x As %String) As %Boolean
{
	SET x=$TRANSLATE(x," ")
	// https://leiq.bus.umich.edu/res_codes_cusip.htm
	IF x'?8UNP1N QUIT 0
	SET cd=$EXTRACT(x,*), x=$EXTRACT(x,1,*-1), t=0
	FOR i=1:1:$LENGTH(x) {
		SET n=$EXTRACT(x,i)
		IF n'=+n SET n=$CASE(n,"*":36,"@":37,"#":38,:$ASCII(n)-55)
		IF i#2=0 SET n=n*2
		SET t=t+(n\10)+(n#10)
	}
	QUIT cd=((10-(t#10))#10)
}

}
Examples:
USER>For  { Read s Quit:s=""  Write ": "_##class(Utils.Check).CUSIP(s), ! }         
037833100: 1
17275R102: 1
38259P508: 1
594918104: 1
68389X106: 0
68389X105: 1

USER>

Clojure

(defn- char->value
  "convert the given char c to a value used to calculate the cusip check sum"
  [c]
  (let [int-char (int c)]
    (cond
      (and (>= int-char (int \0)) (<= int-char (int \9))) (- int-char 48)
      (and (>= int-char (int \A)) (<= int-char (int \Z))) (- int-char 55)
      (= c \*) 36
      (= c \@) 37
      (= c \#) 38
      :else nil)))

(defn- calc-sum
  "Calculate cusip sum. nil is returned for an invalid cusip."
  [cusip]
  (reduce
    (fn [sum [i c]]
      (if-let [v (char->value c)]
        (let [v (if (= (mod i 2) 1) (* v 2) v)]
          (+ sum (int (+ (/ v 10) (mod v 10)))))
        (reduced nil)))
    0
    (map-indexed vector (subs cusip 0 8))))

(defn calc-cusip-checksum
  "Given a valid 8 or 9 digit cusip, return the 9th checksum digit"
  [cusip]
  (when (>= (count cusip) 8)
    (let [sum (calc-sum cusip)]
      (when sum
        (mod (- 10 (mod sum 10)) 10)))))

(defn is-valid-cusip9?
  "predicate validating a 9 digit cusip."
  [cusip9]
  (when-let [checksum (and (= (count cusip9) 9)
                           (calc-cusip-checksum cusip9))]
    (= (- (int (nth cusip9 8)) 48)
       checksum)))

(defn rosetta-output
  "show some nice output for the Rosetta Wiki"
  []
  (doseq [cusip ["037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105" "EXTRACRD8"
                 "EXTRACRD9" "BADCUSIP!" "683&9X106" "68389x105" "683$9X106" "68389}105" "87264ABE4"]]
    (println cusip (if (is-valid-cusip9? cusip) "valid" "invalid"))))
Output:
(rosetta-output)
037833100 valid
17275R102 valid
38259P508 valid
594918104 valid
68389X106 invalid
68389X105 valid
EXTRACRD8 invalid
EXTRACRD9 valid
BADCUSIP! invalid
683&9X106 invalid
68389x105 invalid
683$9X106 invalid
68389}105 invalid
87264ABE4 valid

CLU

valid_cusip = proc (s: string) returns (bool)
    own chars: string := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#"
    if string$size(s) ~= 9 then return(false) end
    sum: int := 0
    for i: int in int$from_to(1,8) do
        v: int := string$indexc(s[i], chars)-1
        if v<0 then return(false) end
        if i//2=0 then v := v*2 end
        sum := sum + v/10 + v//10
    end
    check: int := (10 - sum // 10) // 10
    return(check = string$indexc(s[9], chars)-1)
end valid_cusip

start_up = proc ()
    po: stream := stream$primary_output()
    cusips: array[string] := array[string]$[
        "037833100",
        "17275R102",
        "38259P508",
        "594918104",
        "68389X106",
        "68389X105"
    ]
    
    for cusip: string in array[string]$elements(cusips) do
        stream$puts(po, cusip || ": ")
        if valid_cusip(cusip)
            then stream$putl(po, "valid")
            else stream$putl(po, "invalid")
        end 
    end
end start_up
Output:
037833100: valid
17275R102: valid
38259P508: valid
594918104: valid
68389X106: invalid
68389X105: valid

Common Lisp

(defun char->value (c)
  (cond ((digit-char-p c 36))
        ((char= c #\*) 36)
        ((char= c #\@) 37)
        ((char= c #\#) 38)
        (t (error "Invalid character: ~A" c))))

(defun cusip-p (cusip)
  (and (= 9 (length cusip))
       (loop for i from 1 to 8
             for c across cusip
             for v = (char->value c)
             when (evenp i)
               do (setf v (* 2 v))
             sum (multiple-value-bind (quot rem) (floor v 10)
                   (+ quot rem))
               into sum
             finally (return (eql (digit-char-p (char cusip 8))
                                  (mod (- 10 (mod sum 10)) 10))))))

(defun main ()
  (dolist (cusip '("037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105"))
    (format t "~A: ~A~%" cusip (cusip-p cusip))))
Output:
037833100: T
17275R102: T
38259P508: T
594918104: T
68389X106: NIL
68389X105: T

D

import std.stdio;

void main(string[] args) {
    writeln("CUSIP       Verdict");
    foreach(arg; args[1..$]) {
        writefln("%9s : %s", arg, isValidCusip(arg) ? "Valid" : "Invalid");
    }
}

class IllegalCharacterException : Exception {
    this(string msg) {
        super(msg);
    }
}

bool isValidCusip(string cusip) in {
    assert(cusip.length == 9, "Incorrect cusip length");
} body {
    try {
        auto check = cusipCheckDigit(cusip);
        return cusip[8] == ('0' + check);
    } catch (IllegalCharacterException e) {
        return false;
    }
}

unittest {
    // Oracle Corporation
    assertEquals(isValidCusip("68389X105"), true);

    // Oracle Corporation (invalid)
    assertEquals(isValidCusip("68389X106"), false);
}

int cusipCheckDigit(string cusip) in {
    assert(cusip.length == 9, "Incorrect cusip length");
} body {
    int sum;
    for (int i=0; i<8; ++i) {
        char c = cusip[i];
        int v;

        switch(c) {
            case '0': .. case '9':
                v = c - '0';
                break;
            case 'A': .. case 'Z':
                v = c - 'A' + 10;
                break;
            case '*':
                v = 36;
                break;
            case '@':
                v = 37;
                break;
            case '#':
                v = 38;
                break;
            default:
                throw new IllegalCharacterException("Saw character: " ~ c);
        }
        if (i%2 == 1) {
            v = 2 * v;
        }

        sum = sum + (v / 10) + (v % 10);
    }

   return (10 - (sum % 10)) % 10;
}

unittest {
    // Apple Incorporated
    assertEquals(cusipCheckDigit("037833100"), 0);

    // Cisco Systems
    assertEquals(cusipCheckDigit("17275R102"), 2);

    // Google Incorporated
    assertEquals(cusipCheckDigit("38259P508"), 8);

    // Microsoft Corporation
    assertEquals(cusipCheckDigit("594918104"), 4);

    // Oracle Corporation
    assertEquals(cusipCheckDigit("68389X105"), 5);
}

version(unittest) {
    void assertEquals(T)(T actual, T expected) {
        import core.exception;
        import std.conv;
        if (actual != expected) {
            throw new AssertError("Actual [" ~ to!string(actual) ~ "]; Expected [" ~ to!string(expected) ~ "]");
        }
    }
}

/// Invoke with `cusip 037833100 17275R102 38259P508 594918104 68389X106 68389X105`
Output:
CUSIP       Verdict
037833100 : Valid
17275R102 : Valid
38259P508 : Valid
594918104 : Valid
68389X106 : Invalid
68389X105 : Valid

Delphi

Works with: Delphi version 6.0

Using sets to simplify string parsing

type TCUSIPInfo = record
 ID,Company: string;
 end;

var CUSIPArray: array [0..5] of TCUSIPInfo = (
  (ID:'037833100'; Company: 'Apple Incorporated'),
  (ID:'17275R102'; Company: 'Cisco Systems'),
  (ID:'38259P508'; Company: 'Google Incorporated'),
  (ID:'594918104'; Company: 'Microsoft Corporation'),
  (ID:'68389X106'; Company: 'Oracle Corporation'),
  (ID:'68389X105'; Company: 'Oracle Corporation'));

function IsValidCUSIP(Info: TCUSIPInfo): boolean;
{Calculate checksum on first 7 chars of CUSIP }
{And compare with the last char - the checksum char}
var I,V,Sum: integer;
var C: char;
begin
Sum:=0;
for I:=1 to Length(Info.ID)-1 do
	begin
	C:=Info.ID[I];
	if C in ['0'..'9'] then V:=byte(C)-$30
	else if C in ['A'..'Z'] then V:=(byte(C)-$40) + 9
	else case C of
	 '*': V:=36;
	 '@': V:=37;
	 '#': V:=38;
	 end;
	if (I and 1)=0 then V:=V*2;
	Sum:=Sum + (V div 10) + (V mod 10);
	end;
Sum:=(10 - (Sum mod 10)) mod 10;
Result:=StrToInt(Info.ID[Length(Info.ID)])=Sum;
end;


procedure TestCUSIPList(Memo: TMemo);
{Test every item in the CSUIP array}
var I: integer;
var S: string;
begin
for I:=0 to High(CUSIPArray) do
	begin
	if IsValidCUSIP(CUSIPArray[I]) then S:='Valid' else S:='Invalid';
	Memo.Lines.Add(CUSIPArray[I].ID+'	'+CUSIPArray[I].Company+':	'+S);
	end;
end;
Output:
037833100	Apple Incorporated:	Valid
17275R102	Cisco Systems:		Valid
38259P508	Google Incorporated:	Valid
594918104	Microsoft Corporation:	Valid
68389X106	Oracle Corporation:	Invalid
68389X105	Oracle Corporation:	Valid


Dyalect

Translation of: Go
func isCusip(s) {
    if s.Length() != 9 { return false }
    var sum = 0
    for i in 0..7 {
        var c = s[i]
        var v =
            match c {
                '0'..'9' => c.Order() - 48,
                'A'..'Z' => c.Order() - 55,
                '*' => 36,
                '@' => 37,
                '#' => 38,
                _ => false
            }
        if i % 2 == 1 { v *= 2 }
        sum += v / 10 + v % 10
    }
    s[8].Order() - 48 == (10 - (sum % 10)) % 10
}
 
var candidates = [
    "037833100",
    "17275R102",
    "38259P508",
    "594918104",
    "68389X106",
    "68389X105"
]
 
for candidate in candidates {
    var b =
        if isCusip(candidate) {
            "correct"
        } else {
            "incorrect"
        }
    print("\(candidate) -> \(b)")
}
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

EasyLang

func check inp$ .
   for i = 1 to 8
      c = strcode substr inp$ i 1
      if c >= 48 and c <= 57
         v = c - 48
      elif c >= 65 and c <= 91
         v = c - 64 + 9
      elif c = 42
         v = 36
      elif c = 64
         v = 37
      elif c = 35
         v = 38
      .
      if i mod 2 = 0
         v *= 2
      .
      sum += v div 10 + v mod 10
   .
   return if (10 - (sum mod 10)) mod 10 = number substr inp$ 9 1
.
for s$ in [ "037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105" ]
   write s$ & " is "
   if check s$ = 1
      print "valid"
   else
      print "invalid"
   .
.


Excel

LAMBDA

Binding the names ISCUSIP and CUSIPMAP to the following lambda expressions in the Name Manager of the Excel WorkBook:

(See LAMBDA: The ultimate Excel worksheet function)

=LAMBDA(s,
    LET(
        ns, VLOOKUP(
            CHARS(s), CUSIPMAP, 2, FALSE
        ),
        
        AND(
            9 = COLUMNS(ns),
            LET(
                firstEight, INITCOLS(ns),
                
                ixs, SEQUENCE(1, 8),
                
                evensDoubled, IF(ISEVEN(ixs),
                    2 * INDEX(firstEight, 1, ixs),
                    INDEX(firstEight, 1, ixs)
                ),
                
                LASTCOL(ns) = MOD(
                    10 - MOD(
                        SUM(
                            QUOTIENT(evensDoubled, 10),
                            MOD(evensDoubled, 10)
                        ), 
                        10
                    ), 
                    10
                )
            )
        )
    )
)


CUSIPMAP
={"0",0;"1",1;"2",2;"3",3;"4",4;"5",5;"6",6;"7",7;"8",8;"9",9;"A",
10;"B",11;"C",12;"D",13;"E",14;"F",15;"G",16;"H",17;"I",18;"J",19;"K",
20;"L",21;"M",22;"N",23;"O",24;"P",25;"Q",26;"R",27;"S",28;"T",29;"U",
30;"V",31;"W",32;"X",33;"Y",34;"Z",35;"*",36;"@",37;"#",38}

and also assuming the following generic bindings in the Name Manager for the WorkBook:

CHARS
=LAMBDA(s,
    MID(
        s,
        SEQUENCE(1, LEN(s), 1, 1),
        1
    )
)


INITCOLS
=LAMBDA(xs,
    INDEX(
        xs,
        SEQUENCE(
            1,
            COLUMNS(xs) - 1,
            1,
        )
    )
)


LASTCOL
=LAMBDA(xs,
    INDEX(
        xs,
        SEQUENCE(ROWS(xs), 1, 1, 1),
        COLUMNS(xs)
    )
)
Output:
fx =ISCUSIP(A2)
A B
1 Strings CUSIP verdicts
2 037833100 TRUE
3 17275R102 TRUE
4 38259P508 TRUE
5 594918104 TRUE
6 68389X106 FALSE
7 68389X105 TRUE

F#

// Validate CUSIP: Nigel Galloway. June 2nd., 2021
let fN=function n when n>47 && n<58->n-48 |n when n>64 && n<91->n-55 |42->36 |64->37 |_->38
let cD(n:string)=(10-(fst((n.[0..7])|>Seq.fold(fun(z,n)g->let g=(fN(int g))*(n+1) in (z+g/10+g%10,(n+1)%2))(0,0)))%10)%10=int(n.[8])-48
["037833100";"17275R102";"38259P508";"594918104";"68389X103";"68389X105"]|>List.iter(fun n->printfn "CUSIP %s is %s" n (if cD n then "valid" else "invalid"))
Output:
CUSIP 037833100 is valid
CUSIP 17275R102 is valid
CUSIP 38259P508 is valid
CUSIP 594918104 is valid
CUSIP 68389X103 is invalid
CUSIP 68389X105 is valid
Real: 00:00:00.009

Factor

USING: combinators.short-circuit formatting kernel math
math.parser qw regexp sequences unicode ;
IN: rosetta-code.cusip

: cusip-check-digit ( seq -- n )
    but-last-slice [
        [ dup alpha? [ digit> ] [ "*@#" index 36 + ] if ] dip
        odd? [ 2 * ] when 10 /mod +
    ] map-index sum 10 mod 10 swap - 10 mod ;

: cusip? ( seq -- ? )
    {
        [ R/ [0-9A-Z*@#]+/ matches? ]
        [ [ last digit> ] [ cusip-check-digit ] bi = ]
    } 1&& ;

qw{ 037833100 17275R102 38259P508 594918104 68389X106 68389X105 }
[ dup cusip? "correct" "incorrect" ? "%s -> %s\n" printf ] each
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

Fortran

The key notion here is to employ a single sequence of valid characters, VALID, and for each character C of the code under test, use function INDEX(VALID,C) to find its position within that sequence, which turns out to be the desired v of the example pseudocode. The only slight difficulty is that INDEX starts its counting with one for the first character of VALID, which is zero, so one must be subtracted; similarly, to return a digit character code via indexing into VALID, one must be added. By using a list of valid characters rather than peculiar character arithmetic (such as c <= "9" & c >= "0" or similar) there is no reliance on the ASCII way of things. Recall that EBCDIC encodements have different orderings and notably, non-alphabetic characters between A and Z.

The source does not bother with the MODULE protocol of F90 and later, and so the type of function CUSIPCHECK must be declared in all routines wishing to invoke it. However, the F90 feature of having the END statement of a subroutine or function give its name is to valuable to ignore. The function returns a character code rather than an integer, since the presumption is that it is to be compared to the check character of the code being inspected, which is known as a character not an integer. This means some blather when extracting the eight characters to be presented to CUSIPCHECK and comparing the result to the ninth character, but the test can be done in one expression.

There is no checking that only valid characters are presented, nor that eight-character codes only are offered, though the compiler might complain if the function were to be invoked with a text literal of the wrong size. In the absence of such checks, there need be no added complications to support a scheme for reporting such errors.

      CHARACTER*1 FUNCTION CUSIPCHECK(TEXT)	!Determines the check sum character.
Committee on Uniform Security Identification Purposes, of the American (i.e. USA) Bankers' Association.
       CHARACTER*8 TEXT		!Specifically, an eight-symbol code.
       CHARACTER*(*) VALID	!These only are valid.
       PARAMETER (VALID = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#")
       INTEGER I,V,S		!Assistants.
        S = 0		!Start the checksum.
        DO I = 1,LEN(TEXT)	!Step through the text.
          V = INDEX(VALID,TEXT(I:I)) - 1	!Since counting starts with one.
          IF (MOD(I,2).EQ.0) V = V*2		!V = V*(2 - MOD(I,2))?
          S = S + V/10 + MOD(V,10)		!Specified calculation.
        END DO			!On to the next character.
        I = MOD(10 - MOD(S,10),10) + 1	!Again, counting starts with one.
        CUSIPCHECK = VALID(I:I)	!Thanks to the MOD 10, surely a digit.
      END FUNCTION CUSIPCHECK	!No checking for invalid input...

      PROGRAM POKE	!Just to try it out.
      INTEGER I,N	!Assistants.
      PARAMETER (N = 6)		!A whole lot of blather
      CHARACTER*9 CUSIP(N)	!Just to have an array of test codes.
      DATA CUSIP/		!Here they are, as specified.
     1  "037833100",
     2  "17275R102",
     3  "38259P508",
     4  "594918104",
     5  "68389X106",
     6  "68389X105"/
      CHARACTER*1 CUSIPCHECK	!Needed as no use of the MODULE protocol.

      DO I = 1,N	!"More than two? Use a DO..."
        WRITE (6,*) CUSIP(I),CUSIPCHECK(CUSIP(I)(1:8)).EQ.CUSIP(I)(9:9)
      END DO

      END

Output: standard output is to I/O unit 6, and free-format (the *) will suffice for this. Each line output starts with a space (in case it is to go to a lineprinter, with carriage control), which is convenient for layout here.

037833100 T
17275R102 T
38259P508 T
594918104 T
68389X106 F
68389X105 T

This would have worked first time, except that a fymgre frmble caused the omission of the digit 2 from the text of VALID. The benefits of checking checksums reach to unexpected places!


FutureBasic

include "NSLog.incl"

local fn VerifyCUSIP( cusipStr as CFStringRef ) as CFStringRef
  NSUInteger   i, v, sum = 0, count = len(cusipStr)
  CFStringRef  resultStr
  
  if count != 9 then exit fn = @"Invalid length"
  
  for i = 0 to 7
    unichar x = fn StringCharacterAtIndex( cusipStr, i )
    select x
      case _"*" : v = 36
      case _"@" : v = 37
      case _"#" : v = 38
      case else
        if ( x >= _"0" and x <= _"9" )
          v = x - _"0"
        else
          if ( x >= _"A" and x <= _"Z" )
            v = x - _"A" + 10
          else
            exit fn = fn StringWithFormat( @"Invalid character: %c", x )
          end if
        end if
    end select
    
    if ( i and 1 ) then v = v * 2
    
    sum += (v / 10) + (v mod 10)
  next
  sum = ((10-(sum mod 10)) mod 10)
  
  if (sum == ( fn StringCharacterAtIndex( cusipStr, 8 ) - _"0" ))
    resultStr = @"Valid"
  else
    resultStr = @"Invalid"
  end If
end fn = resultStr

NSLog( @"0378331009: %@", fn VerifyCUSIP( @"0378331009" ) ) // Invalid length expected
NSLog( @"037833100:  %@", fn VerifyCUSIP( @"037833100"  ) ) // Valid expected
NSLog( @"17275R102:  %@", fn VerifyCUSIP( @"17275R102"  ) ) // Valid expected
NSLog( @"38259P508:  %@", fn VerifyCUSIP( @"38259P508"  ) ) // Valid expected
NSLog( @"594918104:  %@", fn VerifyCUSIP( @"594918104"  ) ) // Valid expected
NSLog( @"68389X106:  %@", fn VerifyCUSIP( @"68389X106"  ) ) // Invalid expected
NSLog( @"68389X105:  %@", fn VerifyCUSIP( @"68389X105"  ) ) // Valid expected
NSLog( @"683&9X105:  %@", fn VerifyCUSIP( @"683&9X105"  ) ) // Invalid character expected: &

HandleEvents
Output:
0378331009: Invalid length
037833100:  Valid
17275R102:  Valid
38259P508:  Valid
594918104:  Valid
68389X106:  Invalid
68389X105:  Valid
683&9X105:  Invalid character: &

Go

package main

import "fmt"

func isCusip(s string) bool {
    if len(s) != 9 { return false }
    sum := 0
    for i := 0; i < 8; i++ {
        c := s[i]
        var v int
        switch {
            case c >= '0' && c <= '9':
                v = int(c) - 48
            case c >= 'A' && c <= 'Z':
                v = int(c) - 55
            case c == '*':
                v = 36
            case c == '@':
                v = 37
            case c == '#':
                v = 38
            default:
                return false
        }
        if i % 2 == 1 { v *= 2 }  // check if odd as using 0-based indexing
        sum += v/10 + v%10
    }
    return int(s[8]) - 48 == (10 - (sum%10)) % 10
}

func main() {
    candidates := []string {
        "037833100",
        "17275R102",
        "38259P508",
        "594918104",
        "68389X106",
        "68389X105",
    }

    for _, candidate := range candidates {
        var b string
        if isCusip(candidate) {
            b = "correct"
        } else {
            b = "incorrect"
        }
        fmt.Printf("%s -> %s\n", candidate, b)
    }
}
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

Groovy

Translation of: Java
class Cusip {
    private static Boolean isCusip(String s) {
        if (s.length() != 9) return false
        int sum = 0
        for (int i = 0; i <= 7; i++) {
            char c = s.charAt(i)

            int v
            if (c >= ('0' as char) && c <= ('9' as char)) {
                v = c - 48
            } else if (c >= ('A' as char) && c <= ('Z' as char)) {
                v = c - 55  // lower case letters apparently invalid
            } else if (c == '*' as char) {
                v = 36
            } else if (c == '@' as char) {
                v = 37
            } else if (c == '#' as char) {
                v = 38
            } else {
                return false
            }
            if (i % 2 == 1) v *= 2  // check if odd as using 0-based indexing
            sum += v / 10 + v % 10
        }
        return s.charAt(8) - 48 == (10 - (sum % 10)) % 10
    }

    static void main(String[] args) {
        List<String> candidates=new ArrayList<>()
        candidates.add("037833100")
        candidates.add("17275R102")
        candidates.add("38259P508")
        candidates.add("594918104")
        candidates.add("68389X106")
        candidates.add("68389X105")
        for (String candidate : candidates) {
            System.out.printf("%s -> %s%n", candidate, isCusip(candidate) ? "correct" : "incorrect")
        }
    }
}
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

Haskell

import Data.List(elemIndex)

data Result = Valid | BadCheck | TooLong | TooShort | InvalidContent deriving Show

-- convert a list of Maybe to a Maybe list.
-- result is Nothing if any of values from the original list are Nothing
allMaybe :: [Maybe a] -> Maybe [a]
allMaybe = sequence

toValue :: Char -> Maybe Int
toValue c = elemIndex c $ ['0'..'9'] ++ ['A'..'Z'] ++ "*@#" 

-- check a list of ints to see if they represent a valid CUSIP
valid :: [Int] -> Bool
valid ns0 = 
    let -- multiply values with even index by 2
        ns1 = zipWith (\i n -> (if odd i then n else 2*n)) [1..] $ take 8 ns0

        -- apply div/mod formula from site and sum up results
        sm = sum $ fmap (\s -> ( s `div` 10 ) + s `mod` 10) ns1

    in  -- apply mod/mod formula from site and compare to last value in list
        ns0!!8 == (10 - (sm `mod` 10)) `mod` 10

-- check a String to see if it represents a valid CUSIP
checkCUSIP :: String -> Result
checkCUSIP cs 
       | l < 9     = TooShort
       | l > 9     = TooLong
       | otherwise = case allMaybe (fmap toValue cs) of
                         Nothing -> InvalidContent
                         Just ns -> if valid ns then Valid else BadCheck
    where l = length cs

testData =  
    [ "037833100"
    , "17275R102"
    , "38259P508"
    , "594918104"
    , "68389X106"
    , "68389X105"
    ]

main = mapM_ putStrLn (fmap (\s -> s ++ ": " ++ show (checkCUSIP s)) testData)
Output:
037833100: Valid
17275R102: Valid
38259P508: Valid
594918104: Valid
68389X106: BadCheck
68389X105: Valid

Or, picking some other possibilities from Haskell's rich libraries:

import qualified Data.Map as M (Map, fromList, lookup)
import Data.Maybe (fromMaybe)

-------------------------- CUSIP -------------------------

cusipMap :: M.Map Char Int
cusipMap =
  M.fromList $
    zip (['0' .. '9'] <> ['A' .. 'Z'] <> "*@#") [0 ..]

cusipValid :: String -> Bool
cusipValid s =
  let ns = (fromMaybe [] . traverse (`M.lookup` cusipMap)) s
   in (9 == length ns)
        && let qrSum =
                 sum $
                   ( [quot, rem]
                       <*> zipWith
                         id
                         (cycle [id, (* 2)])
                         (take 8 ns)
                   )
                     <*> [10]
            in last ns == rem (10 - rem qrSum 10) 10

--------------------------- TEST -------------------------
main :: IO ()
main =
  mapM_
    (print . ((,) <*> cusipValid))
    [ "037833100",
      "17275R102",
      "38259P508",
      "594918104",
      "68389X106",
      "68389X105"
    ]
Output:
("037833100",True)
("17275R102",True)
("38259P508",True)
("594918104",True)
("68389X106",False)
("68389X105",True)

Icon and Unicon

# cusip.icn -- Committee on Uniform Security Identification Procedures

procedure main()
   local code, codes
   codes := ["037833100", "17275R102", "38259P508",
            "594918104", "68389X106", "68389X105"]
   while code := pop(codes) do {
      writes(code, " : ")
      if check_code(code) then
         write("valid.")
      else write("not valid.")
      }
end

procedure check_code(c)
   local p, sum, value
   static codetable
   initial codetable := buildtable()

   sum   := 0
   value := 0
   every p := 1 to 8 do {
      if p % 2 = 1 then    # odd position
         value := codetable[c[p]] 
      else                 # even position
         value := 2 * codetable[c[p]]
      sum +:= (value / 10) + (value % 10)
      }
   sum := (10 - (sum % 10)) % 10
   if sum = c[9] then return else fail
end

procedure buildtable()
   local chars, n, t
   t := table()
   chars := &digits || &ucase || "*@#"
   every n := 1 to *chars do
      t[chars[n]] := (n - 1)
   return t
end
Output:
037833100 : valid.

17275R102 : valid. 38259P508 : valid. 594918104 : valid. 68389X106 : not valid. 68389X105 : valid.

J

One-liner:

   ccd =. 10 | 10 - 10 | [: +/ [: , 10 (#.^:_1) (8 $ 1 2) * '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#' i. ]
   ccd '68389X10'
5

More verbose version that checks for correct input:

   CUSIPcheckdigit =. 3 : 0
assert. 8 = $ y NB. Only accept an 8-element long list
assert. */ y e. '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#' NB. Only accept characters from the list of 38
values =. (8 $ 1 2) * '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#' i. ] NB. Verb to translate characters and then double every second value.
sumdigits =. +/@,@(10 10&#:) NB. Verb to sum the base-10 digits in a numerical array
invertedmod =. 10 | 10 - 10 | ] NB. Verb to find the mod-10 of 10 minus mod-10
": invertedmod sumdigits values y NB. Return the check digit as a character
)
   addCUSIPcheckdigit =: , CUSIPcheckdigit
   verifyCUSIPcheckdigit =: {: = CUSIPcheckdigit@}:

Examples:

   addCUSIPcheckdigit '68389X10'
68389X105
   verifyCUSIPcheckdigit '68389X106'
0
   verifyCUSIPcheckdigit '68389X105'
1
   samples =: '037833100', '17275R102', '38259P508', '594918104', '68389X106',: '68389X105'
   samples ; verifyCUSIPcheckdigit"1 samples
┌─────────┬─┐
0378331001
17275R1021
38259P5081
5949181041
68389X1060
68389X1051
└─────────┴─┘

Java

Translation of: Kotlin

Uses Java 9

import java.util.List;

public class Cusip {
    private static Boolean isCusip(String s) {
        if (s.length() != 9) return false;
        int sum = 0;
        for (int i = 0; i <= 7; i++) {
            char c = s.charAt(i);

            int v;
            if (c >= '0' && c <= '9') {
                v = c - 48;
            } else if (c >= 'A' && c <= 'Z') {
                v = c - 55;  // lower case letters apparently invalid
            } else if (c == '*') {
                v = 36;
            } else if (c == '@') {
                v = 37;
            } else if (c == '#') {
                v = 38;
            } else {
                return false;
            }
            if (i % 2 == 1) v *= 2;  // check if odd as using 0-based indexing
            sum += v / 10 + v % 10;
        }
        return s.charAt(8) - 48 == (10 - (sum % 10)) % 10;
    }

    public static void main(String[] args) {
        List<String> candidates = List.of(
                "037833100", "17275R102", "38259P508", "594918104", "68389X106", "68389X105", "EXTRACRD8",
                "EXTRACRD9", "BADCUSIP!", "683&9X106", "68389x105", "683$9X106", "68389}105", "87264ABE4"
        );
        for (String candidate : candidates) {
            System.out.printf("%s -> %s%n", candidate, isCusip(candidate) ? "correct" : "incorrect");
        }
    }
}
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct
EXTRACRD8 -> incorrect
EXTRACRD9 -> correct
BADCUSIP! -> incorrect
683&9X106 -> incorrect
68389x105 -> incorrect
683$9X106 -> incorrect
68389}105 -> incorrect
87264ABE4 -> correct

JavaScript

(() => {
    '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();
})();
Output:
037833100 -> true
17275R102 -> true
38259P508 -> true
594918104 -> true
68389X106 -> false
68389X105 -> true

jq

Adapted from Wren

Works with: jq

Also works with gojq, the Go implementation of jq, and with jackson-jq and fq.

def isCusip:
  length == 9 and
  explode as $s
  | {sum: 0, i: 0}
  | until(. == false or .i == 8;
      $s[.i] as $c
      | (if ($c >= 48 and $c <= 57)    # '0' to '9'
         then $c - 48
         elif ($c >= 65 and $c <= 90)  # 'A' to 'Z'
         then $c - 55
         elif $c == 42                 # '*'
         then 36
         elif $c == 64                 # '@'
         then 37
         elif $c == 35                 # '#'
         then 38
         else false                    # return false
         end ) as $v
      | if $v == false then false
        else # check if odd as using 0-based indexing
            (if (.i%2 == 1) then 2 * $v else $v end) as $v
        | .sum += (($v/10)|floor) + $v%10 
        | .i += 1
        end )
  | if . == false then false
    else $s[8] - 48 == (10 - (.sum%10)) % 10
    end;

def candidates: [
    "037833100",
    "17275R102",
    "38259P508",
    "594918104",
    "68389X106",
    "68389X105"
];

candidates[]
| "\(.) -> \(if isCusip then "correct" else "incorrect" end)"
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

Julia

Works with: Julia version 0.6
module CUSIP

function _lastdigitcusip(input::AbstractString)
    input = uppercase(input)
    s = 0

    for (i, c) in enumerate(input)
        if isdigit(c)
            v = Int(c) - 48
        elseif isalpha(c)
            v = Int(c) - 64 + 9
        elseif c == '*'
            v = 36
        elseif c == '@'
            v = 37
        elseif c == '#'
            v = 38
        end

        if iseven(i); v *= 2 end
        s += div(v, 10) + rem(v, 10)
    end

    return Char(rem(10 - rem(s, 10), 10) + 48)
end

checkdigit(input::AbstractString) = input[9] == _lastdigitcusip(input[1:8])

end  # module CUSIP

for code in ("037833100", "17275R102", "38259P508", "594918104", "68389X106", "68389X105")
    println("$code is ", CUSIP.checkdigit(code) ? "correct." : "not correct.")
end
Output:
037833100 is correct.
17275R102 is correct.
38259P508 is correct.
594918104 is correct.
68389X106 is not correct.
68389X105 is correct.

Kotlin

// version 1.1.0

fun isCusip(s: String): Boolean {
    if (s.length != 9) return false
    var sum = 0
    for (i in 0..7) {
        val c = s[i]
        var v = when (c) {
            in '0'..'9'  -> c.toInt() - 48
            in 'A'..'Z'  -> c.toInt() - 55  // lower case letters apparently invalid
            '*'          -> 36
            '@'          -> 37
            '#'          -> 38
            else         -> return false
        }
        if (i % 2 == 1) v *= 2  // check if odd as using 0-based indexing
        sum += v / 10 + v % 10
    }
    return s[8].toInt() - 48  == (10 - (sum % 10)) % 10
}

fun main(args: Array<String>) {
    val candidates = listOf(
        "037833100",
        "17275R102",
        "38259P508",
        "594918104",
        "68389X106",
        "68389X105"
    )
    for (candidate in candidates) 
        println("$candidate -> ${if(isCusip(candidate)) "correct" else "incorrect"}")
}
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

langur

If we don't strictly follow the pseudo-code, we can do this.

val .isCusip = fn(.s) {
    if .s is not string or len(.s) != 9 {
        return false
    }

    val .basechars = '0'..'9' ~ 'A'..'Z' ~ "*@#"

    val .sum = for[=0] .i of 8 {
        var .v = index(s2s(.s, .i), .basechars)
        if not .v: return false
        .v = .v[1]-1
        if .i div 2: .v *= 2
        _for += .v \ 10 + .v rem 10
    }

    .s[9]-'0' == (10-(.sum rem 10)) rem 10
}

val .candidates = fw/037833100 17275R102 38259P508 594918104 68389X106 68389X105/

for .c in .candidates {
    writeln .c, ": ", if(.isCusip(.c): "good" ; "bad")
}

Following the pseudo-code would look more like the following.

Translation of: Go
val .isCusip = fn(.s) {
    if .s is not string or len(.s) != 9 {
        return false
    }

    val .sum = for[=0] .i of 8 {
        val .c = .s[.i]
        var .v = 0

        switch[and] .c {
            case >= '0', <= '9':
                .v = .c-'0'

            case >= 'A', <= 'Z':
                .v = .c-55 # .c-'A'+10

            case '*': .v = 36
            case '@': .v = 37
            case '#': .v = 38

            default: return false
        }

        if .i div 2: .v *= 2
        _for += .v \ 10 + .v rem 10
    }

    .s[9]-'0' == (10-(.sum rem 10)) rem 10
}

val .candidates = w/037833100 17275R102 38259P508 594918104 68389X106 68389X105/

for .c in .candidates {
    writeln .c, ": ", if(.isCusip(.c): "good" ; "bad")
}
Output:
037833100: good
17275R102: good
38259P508: good
594918104: good
68389X106: bad
68389X105: good

Lua

The checkDigit function is a line-for-line translation of the pseudo-code algorithm.

function checkDigit (cusip)
  if #cusip ~= 8 then return false end
  
  local sum, c, v, p = 0
  for i = 1, 8 do
    c = cusip:sub(i, i)
    if c:match("%d") then
      v = tonumber(c)
    elseif c:match("%a") then
      p = string.byte(c) - 55
      v = p + 9
    elseif c == "*" then
      v = 36
    elseif c == "@" then
      v = 37
    elseif c == "#" then
      v = 38
    end
    if i % 2 == 0 then
      v = v * 2
    end
    
    sum = sum + math.floor(v / 10) + v % 10
  end
  
  return tostring((10 - (sum % 10)) % 10)
end

local testCases = {
  "037833100",
  "17275R102",
  "38259P508",
  "594918104",
  "68389X106",
  "68389X105"
}
for _, CUSIP in pairs(testCases) do
  io.write(CUSIP .. ": ")
  if checkDigit(CUSIP:sub(1, 8)) == CUSIP:sub(9, 9) then
    print("VALID")
  else
    print("INVALID")
  end
end
Output:
037833100: VALID
17275R102: VALID
38259P508: VALID
594918104: VALID
68389X106: INVALID
68389X105: VALID

Mathematica / Wolfram Language

ClearAll[Cusip]
rules = Thread[(ToString /@ Range[0, 9]) -> Range[0, 9]]~Join~
   Thread[CharacterRange["A", "Z"] -> Range[26] + 9]~Join~
   Thread[Characters["*@#"] -> {36, 37, 38}];
Cusip[cusip_String] := Module[{s = cusip, sum = 0, c, value, check},
  If[StringLength[s] != 9,
   Print["Cusip must be 9 characters!"];
   False
   ,
   s = Characters[ToUpperCase[s]];
   Do[
    c = s[[i]];
    value = c /. rules;
    If[EvenQ[i], value *= 2];
    sum += Floor[value/10] + Mod[value, 10];
    ,
    {i, 8}
    ];
   check = Mod[(10 - Mod[sum, 10]), 10];
   s[[-1]] === ToString[check]
   ]
  ]
Cusip /@ {"037833100", "17275R102", "38259P508", "594918104", "68389X106", "68389X105"}
Output:
{True, True, True, True, False, True}

MiniScript

isCusip = function(s)
  if s.len != 9 then return false
  sum = 0
  for i in range(0, 7)
    c = s[i]
    v = 0
    if c >= "0" and c <= "9" then
      v = code(c) - 48
    else if c >= "A" and c <= "Z" then
      v = code(c) - 55
    else if c == "*" then
      v = 36
    else if c == "@" then
      v = 37
    else if c == "#" then
      v = 38
    else
      return false
    end if
    if i%2 == 1 then v *= 2 // check if odd as using 0-based indexing
    sum += floor(v/10) + v%10
  end for
  return code(s[8]) - 48 == (10 - (sum%10)) % 10
end function

candidates = [
  "037833100", "17275R102", "38259P508",
  "594918104", "68389X106", "68389X105",
]
for candidate in candidates
  s = "valid"
  if not isCusip(candidate) then s = "invalid"
  print candidate + " -> " + s
end for
Output:
037833100 -> valid
17275R102 -> valid
38259P508 -> valid
594918104 -> valid
68389X106 -> invalid
68389X105 -> valid

Modula-2

MODULE CUSIP;
FROM FormatString IMPORT FormatString;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;

PROCEDURE WriteInt(n : INTEGER);
VAR buf : ARRAY[0..10] OF CHAR;
BEGIN
    FormatString("%i", buf, n);
    WriteString(buf)
END WriteInt;

PROCEDURE cusipCheckDigit(cusip : ARRAY OF CHAR) : INTEGER;
VAR
    i,v,sum : INTEGER;
BEGIN
    i := 0;
    sum := 0;
    WHILE cusip[i] # 0C DO
        IF ('0' <= cusip[i]) AND (cusip[i] <= '9') THEN
            v := ORD(cusip[i]) - 48 (* 0 *)
        ELSIF ('A' <= cusip[i]) AND (cusip[i] <= 'Z') THEN
            v := ORD(cusip[i]) - 65 (* A *) + 10
        ELSIF cusip[i] = '*' THEN
            v := 36
        ELSIF cusip[i] = '@' THEN
            v := 37
        ELSIF cusip[i] = '#' THEN
            v := 38
        ELSE
            RETURN -1
        END;
        IF i MOD 2 = 1 THEN v := 2 * v END;
        IF i < 8 THEN
            sum := sum + (v DIV 10) + (v MOD 10);
        END;
        INC(i)
    END;

    IF i # 9 THEN RETURN -1 END;
    RETURN (10 - (sum MOD 10)) MOD 10
END cusipCheckDigit;

PROCEDURE isValidCusip(cusip : ARRAY OF CHAR) : BOOLEAN;
VAR
    check : INTEGER;
BEGIN
    check := cusipCheckDigit(cusip);
    IF check < 0 THEN RETURN FALSE END;
    RETURN cusip[8] = CHR(48 (* 0 *) + check)
END isValidCusip;

PROCEDURE Print(cusip : ARRAY OF CHAR);
BEGIN
    WriteString(cusip);
    IF isValidCusip(cusip) THEN
        WriteString(" : Valid")
    ELSE
        WriteString(" : Invalid")
    END;
    WriteLn
END Print;

(* main *)
BEGIN
    WriteString("CUSIP       Verdict");
    WriteLn;

    Print("037833100");
    Print("17275R102");
    Print("38259P508");
    Print("594918104");
    Print("68389X106");
    Print("68389X105");

    ReadChar
END CUSIP.
Output:
CUSIP       Verdict
037833100 : Valid
17275R102 : Valid
38259P508 : Valid
594918104 : Valid
68389X106 : Invalid
68389X105 : Valid

Nanoquery

def cusip_checksum(cusip)
    alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    num   = "0123456789"
    sum   = 0

    for i in range(1, 8)
        c = cusip[i - 1]
        v = 0
        if c in num
            v = int(c)
        else if c in alpha
            p = alpha[c] + 1
            v = p + 9
        else if c in "*@#"
            v = "*@#"[c] + 36
        end
        if (i % 2) = 0
            v *= 2
        end

        sum += int(v / 10) + (v % 10)
    end

    return (10 - (sum % 10)) % 10
end

if main
    codes = {"037833100", "17275R102", "38259P508",\
             "594918104", "68389X106", "68389X105"}

    for code in codes
        if int(code[len(code) - 1]) = cusip_checksum(code)
            println code + " is valid"
        else
            println code + " is invalid"
        end
    end
end
Output:
037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
68389X105 is valid

Nim

import strutils

proc cusipCheck(cusip: string): bool =
  if cusip.len != 9:
    return false
  
  var 
    sum, v = 0
  for i, c in cusip[0 .. ^2]:
    if c.isDigit:
      v = parseInt($c)
    elif c.isUpperAscii:
      v = ord(c) - ord('A') + 10
    elif c == '*':
      v = 36
    elif c == '@':
      v = 37
    elif c == '#':
      v = 38
    
    if i mod 2 == 1:
      v *= 2
    
    sum += v div 10 + v mod 10
  let check = (10 - (sum mod 10)) mod 10
  return $check == $cusip[^1]

proc main =
  let codes = [
    "037833100",
    "17275R102",
    "38259P508",
    "594918104",
    "68389X106",
    "68389X105"
  ]

  for code in codes:
    echo code, ": ", if cusipCheck(code): "Valid" else: "Invalid"

main()
Output:
037833100: Valid
17275R102: Valid
38259P508: Valid
594918104: Valid
68389X106: Invalid
68389X105: Valid

Objeck

Translation of: Kotlin
class Cusip {
    function : native : IsCusip(s : String) ~ Bool {
        if(s->Size() <> 9) {
            return false;
        };

        sum := 0;
        for(i := 0; i < 7; i+=1;) {
            c := s->Get(i);
 
            v : Int;
            if (c >= '0' & c <= '9') {
                v := c - 48;
            } else if (c >= 'A' & c <= 'Z') {
                v := c - 55;  # lower case letters apparently invalid
            } else if (c = '*') {
                v := 36;
            } else if (c = '@') {
                v := 37;
            } else if (c = '#') {
                v := 38;
            } else {
                return false;
            };
        
            # check if odd as using 0-based indexing
            if(i % 2 = 1) {
                v *= 2;
            }; 

            sum += v / 10 + v % 10;
        };

        return s->Get(8) - 48 = (10 - (sum % 10)) % 10;
    }
 
    function : Main(args : String[]) ~ Nil {
        candidates := [
            "037833100",
            "17275R102",
            "38259P508",
            "594918104",
            "68389X106",
            "68389X105"
        ];

        each(i : candidates) {
            candidate := candidates[i];
            "{$candidate} => "->Print(); 
            if(IsCusip(candidate)) {
                "correct"->PrintLine();
            }
            else {
                "incorrect"->PrintLine();
            };
        };
    }
}

Output:

037833100 => correct
17275R102 => correct
38259P508 => correct
594918104 => correct
68389X106 => incorrect
68389X105 => correct

Perl

$cv{$_} = $i++ for '0'..'9', 'A'..'Z', '*', '@', '#';

sub cusip_check_digit {
    my @cusip = split m{}xms, shift;
    my $sum = 0;

    for $i (0..7) {
        return 'Invalid character found' unless $cusip[$i] =~ m{\A [[:digit:][:upper:]*@#] \z}xms;
        $v  = $cv{ $cusip[$i] };
        $v *= 2 if $i%2;
        $sum += int($v/10) + $v%10;
    }

    $check_digit = (10 - ($sum%10)) % 10;
    $check_digit == $cusip[8] ? '' : ' (incorrect)';
}

my %test_data = (
    '037833100' => 'Apple Incorporated',
    '17275R102' => 'Cisco Systems',
    '38259P508' => 'Google Incorporated',
    '594918104' => 'Microsoft Corporation',
    '68389X106' => 'Oracle Corporation',
    '68389X105' => 'Oracle Corporation',
);

print "$_ $test_data{$_}" . cusip_check_digit($_) . "\n" for sort keys %test_data;
Output:
037833100 Apple Incorporated
17275R102 Cisco Systems
38259P508 Google Incorporated
594918104 Microsoft Corporation
68389X105 Oracle Corporation
68389X106 Oracle Corporation (incorrect)

Phix

sequence cch = {}
 
function CusipCheckDigit(string cusip)
integer s = 0, c, v
    if length(cch)=0 then
        cch = repeat(-1,256)
        for i='0' to '9' do
            cch[i] = i-'0'
        end for
        for i='A' to 'Z' do
            cch[i] = i-55
        end for
        cch['*'] = 36
        cch['@'] = 37
        cch['#'] = 38
    end if
    if length(cusip)!=9 or find('\0',cusip) then return 0 end if
    for i=1 to 8 do
        c := cusip[i]
        v := cch[c]
        if v=-1 then return 0 end if
        if remainder(i,2)=0 then
            v *= 2
        end if
        s += floor(v/10)+mod(v,10)
    end for
    return cusip[9]=mod(10-mod(s,10),10)+'0'
end function
 
sequence tests = {"037833100",  -- Apple Incorporated
                  "17275R102",  -- Cisco Systems
                  "38259P508",  -- Google Incorporated
                  "594918104",  -- Microsoft Corporation
                  "68389X106",  -- Oracle Corporation   (incorrect)
                  "68389X105"}  -- Oracle Corporation
 
for i=1 to length(tests) do
    string ti = tests[i]
    printf(1,"%s : %s\n",{ti,{"invalid","valid"}[CusipCheckDigit(ti)+1]})
end for
Output:
037833100 : valid
17275R102 : valid
38259P508 : valid
594918104 : valid
68389X106 : invalid
68389X105 : valid

PHP

function IsCusip(string $s) {
    if (strlen($s) != 9) return false;
    $sum = 0;
    for ($i = 0; $i <= 7; $i++) {
        $c = $s[$i];
        if (ctype_digit($c)) {
            // if character is numeric, get character's numeric value
            $v = intval($c);
        } elseif (ctype_alpha($c)) {
            // if character is alphabetic, get character's ordinal position in alphabet
            $position = ord(strtoupper($c)) - ord('A') + 1;
            $v = $position + 9;
        } elseif ($c == "*") {
            $v = 36;
        } elseif ($c == "@") {
            $v = 37;
        } elseif ($c == "#") {
            $v = 38;
        } else {
            return false;
        }
        // is this character position even?
        if ($i % 2 == 1) {
            $v *= 2;
        }
        // calculate the checksum digit
        $sum += floor($v / 10 ) + ( $v % 10 );
    }
    return ord($s[8]) - 48 == (10 - ($sum % 10)) % 10;
}

$cusips = array("037833100",
                "17275R102",
                "38259P508",
                "594918104",
                "68389X106",
                "68389X105");

foreach ($cusips as $cusip) echo $cusip . " -> " . (IsCusip($cusip) ? "valid" : "invalid") . "\n";
Output:
037833100 -> valid
17275R102 -> valid
38259P508 -> valid
594918104 -> valid
68389X106 -> invalid
68389X105 -> valid

PicoLisp

(de cusip (Str)
   (let (Str (mapcar char (chop Str))  S 0)
      (for (I . C) (head 8 Str)
         (let V
            (cond
               ((<= 48 C 57) (- C 48))
               ((<= 65 C 90) (+ 10 (- C 65)))
               ((= C 42) 36)
               ((= C 64) 37)
               ((= C 35) 38) )
            (or
               (bit? 1 I)
               (setq V (>> -1 V)) )
            (inc
               'S
               (+ (/ V 10) (% V 10)) ) ) )
      (=
         (- (last Str) 48)
         (% (- 10 (% S 10)) 10) ) ) )

(println
   (mapcar
      cusip
      (quote
         "037833100"
         "17275R102"
         "38259P508"
         "68389X106"
         "68389X105" ) ) )
Output:
(T T T NIL T)

PowerShell

function Get-CheckDigitCUSIP {
    [CmdletBinding()]
    [OutputType([int])]
    Param ( #  Validate input
        [Parameter(Mandatory=$true, Position=0)]
        [ValidatePattern( '^[A-Z0-9@#*]{8}\d$' )] # @#*
        [ValidateScript({$_.Length -eq 9})]
        [string]
        $cusip
    )
    $sum = 0
    0..7 | ForEach { $c = $cusip[$_] ; $v = $null
        if ([Char]::IsDigit($c)) { $v = [char]::GetNumericValue($c) }
        if ([Char]::IsLetter($c)) { $v = [int][char]$c - [int][char]'A' +10 }
        if ($c -eq '*') { $v = 36 }
        if ($c -eq '@') { $v = 37 }
        if ($c -eq '#') { $v = 38 }
        if($_ % 2){ $v += $v }
        $sum += [int][Math]::Floor($v / 10 ) + ($v % 10)
    }
    [int]$checkDigit_calculated = ( 10 - ($sum % 10) ) % 10
    return( $checkDigit_calculated )
}

function Test-IsCUSIP {
    [CmdletBinding()]
    [OutputType([bool])]
    Param (
        [Parameter(Mandatory=$true, Position=0)]
        [ValidatePattern( '^[A-Z0-9@#*]{8}\d$' )]
        [ValidateScript({$_.Length -eq 9})]
        [string]
        $cusip
    )
    [int]$checkDigit_told = $cusip[-1].ToString()
    $checkDigit_calculated = Get-CheckDigitCUSIP $cusip
    ($checkDigit_calculated -eq $checkDigit_told)
}

$data = @"
037833100`tApple Incorporated
17275R102`tCisco Systems
38259P508`tGoogle Incorporated
594918104`tMicrosoft Corporation
68389X106`tOracle Corporation   (incorrect)
68389X105`tOracle Corporation
"@ -split "`n"
$data |%{ Test-IsCUSIP $_.Split("`t")[0] }
Output:

True True True True False True

Python

Procedural

Requires Python 3.6 for the string template literal in the print statement.

#!/usr/bin/env python3

import math

def cusip_check(cusip):
    if len(cusip) != 9:
        raise ValueError('CUSIP must be 9 characters')

    cusip = cusip.upper()
    total = 0
    for i in range(8):
        c = cusip[i]
        if c.isdigit():
            v = int(c)
        elif c.isalpha():
            p = ord(c) - ord('A') + 1
            v = p + 9
        elif c == '*':
            v = 36
        elif c == '@':
            v = 37
        elif c == '#':
            v = 38

        if i % 2 != 0:
            v *= 2

        total += int(v / 10) + v % 10
    check = (10 - (total % 10)) % 10
    return str(check) == cusip[-1]

if __name__ == '__main__':
    codes = [
            '037833100',
            '17275R102',
            '38259P508',
            '594918104',
            '68389X106',
            '68389X105'
            ]
    for code in codes:
        print(f'{code} -> {cusip_check(code)}')

Output:

037833100 -> True
17275R102 -> True
38259P508 -> True
594918104 -> True
68389X106 -> False
68389X105 -> True

Composition of pure functions

Works with: Python version 3.7

Composing a set of pure functions, including a number of general and reusable abstractions:

'''CUSIP'''

from itertools import (cycle, islice, starmap)
from functools import (reduce)
from operator import (add)
from enum import (Enum)


# isCusip :: Dict -> String -> Bool
def isCusip(dct):
    '''Test for the validity of a CUSIP string in the
       context of a supplied dictionary of char values'''
    def go(s):
        ns = [dct[c] for c in list(s) if c in dct]
        return 9 == len(ns) and (
            ns[-1] == (
                10 - (
                    sum(zipWith(
                        lambda f, x: add(*divmod(f(x), 10))
                    )(cycle([identity, double]))(
                        take(8)(ns)
                    )) % 10
                )
            ) % 10
        )
    return go


# cusipCharDict :: () -> Dict Char Int
def cusipCharDict():
    '''Dictionary of integer values for CUSIP characters'''
    def kv(a, ic):
        i, c = ic
        a[c] = i
        return a
    return reduce(
        kv,
        enumerate(
            enumFromTo('0')('9') + (
                enumFromTo('A')('Z') + list('*&#')
            )
        ),
        {}
    )


# TEST -------------------------------------------------
# main :: IO ()
def main():
    '''Tests'''

    # cusipTest :: String -> Bool
    cusipTest = isCusip(cusipCharDict())

    print(
        tabulated('Valid as CUSIP string:')(
            cusipTest
        )([
            '037833100',
            '17275R102',
            '38259P508',
            '594918104',
            '68389X106',
            '68389X105'
        ])
    )

# GENERIC -------------------------------------------------


# double :: Num -> Num
def double(x):
    '''Wrapped here as a function for the zipWith expression'''
    return 2 * x


# enumFromTo :: Enum a => a -> a -> [a]
def enumFromTo(m):
    '''Enumeration of values [m..n]'''
    def go(x, y):
        t = type(m)
        i = fromEnum(x)
        d = 0 if t != float else (x - i)
        return list(map(
            lambda x: toEnum(t)(d + x),
            range(i, 1 + fromEnum(y))
        ) if int != t else range(x, 1 + y))
    return lambda n: go(m, n)


# fromEnum :: Enum a => a -> Int
def fromEnum(x):
    '''Index integer for enumerable value.'''
    return ord(x) if str == type(x) else (
        x.value if isinstance(x, Enum) else int(x)
    )


# mul :: Num -> Num -> Num
def mul(x):
    '''Function version of (*) operator;
       a curried equivalent of operator.mul'''
    return lambda y: x * y


# identity :: a -> a
def identity(x):
    '''The identity function.
       The usual 'id' is reserved in Python.'''
    return x


# tabulated :: String -> (a -> b) -> [a] -> String
def tabulated(s):
    '''heading -> function -> input List -> tabulated output string'''
    def go(f, xs):
        def width(x):
            return len(str(x))
        w = width(max(xs, key=width))
        return s + '\n' + '\n'.join([
            str(x).rjust(w, ' ') + ' -> ' + str(f(x)) for x in xs
        ])
    return lambda f: lambda xs: go(f, xs)


# take :: Int -> [a] -> [a]
# take :: Int -> String -> String
def take(n):
    '''The prefix of xs of length n,
       or xs itself if n > length xs.'''
    return lambda xs: (
        xs[0:n]
        if isinstance(xs, list)
        else list(islice(xs, n))
    )


# toEnum :: Type -> Int -> a
def toEnum(t):
    '''Enumerable value from index integer'''
    dct = {
        int: int,
        float: float,
        str: chr,
        bool: bool
    }
    return lambda x: dct[t](x) if t in dct else t(x)


# zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
def zipWith(f):
    '''Zipping with a custom (rather than tuple) function'''
    return lambda xs: lambda ys: (
        list(starmap(f, zip(xs, ys)))
    )


# MAIN ---
if __name__ == '__main__':
    main()
Output:
Test for validity as a CUSIP string:

'037833100' -> True
'17275R102' -> True
'38259P508' -> True
'594918104' -> True
'68389X106' -> False
'68389X105' -> True

Quackery

  [ -1 split 0 peek char 0 -
    swap 0 swap 
    witheach
      [ [ dup char 0 char 9 1+ within iff
            [ char 0 - ] done
          dup char A char Z 1+ within iff
            [ char A - 10 + ] done
          dup char * = iff
            [ drop 36 ] done
          dup char @ = iff
            [ drop 37 ] done
          dup char # = iff
            [ drop 38 ] done
          $ "Unexpected character '" swap
          join $ "' in CUSIP." join fail ]
        i^ 1 & if [ 2 * ]
        10 /mod + + ]
    10 mod 10 swap - 10 mod = ]            is cusip ( $ --> b )
    
  [ dup echo$ cusip iff
      [ say " is correct." ]
    else [ say " is incorrect." ]
    cr ]                                   is task  ( $ -->   )
               
  $ "037833100 17275R102 38259P508 594918104 68389X106 68389X105" 
  nest$ witheach task
Output:
037833100 is correct.
17275R102 is correct.
38259P508 is correct.
594918104 is correct.
68389X106 is incorrect.
68389X105 is correct.

Racket

#lang racket
(require srfi/14)

(define 0-char (char->integer #\0))
(define A-char (char->integer #\A))

(define (cusip-value c)  
  (cond
    [(char-set-contains? char-set:digit c)
     (- (char->integer c) 0-char)]
    [(char-set-contains? char-set:upper-case c)
     (+ 10 (- (char->integer c) A-char))]
    [(char=? c #\*) 36]
    [(char=? c #\@) 37]
    [(char=? c #\#) 38]))

(define (cusip-check-digit cusip)
  (modulo
   (- 10
      (modulo
       (for/sum
        ((i (sequence-map add1 (in-range 8))) (c (in-string cusip)))
         (let* ((v (cusip-value c)) (v′ (if (even? i) (* v 2) v)))
           (+ (quotient v′ 10) (modulo v′ 10)))) 10)) 10))

(define (CUSIP? s)
  (char=? (string-ref s (sub1 (string-length s)))
          (integer->char (+ 0-char (cusip-check-digit s)))))

(module+ test
  (require rackunit)         
  (check-true (CUSIP? "037833100"))
  (check-true (CUSIP? "17275R102"))
  (check-true (CUSIP? "38259P508"))
  (check-true (CUSIP? "594918104"))
  (check-false (CUSIP? "68389X106"))
  (check-true (CUSIP? "68389X105")))

no output indicates all tests passed.

Raku

(formerly Perl 6)

Works with: Rakudo version 2017.01
sub divmod ($v, $r) { $v div $r, $v mod $r }
my %chr = (flat 0..9, 'A'..'Z', <* @ #>) Z=> 0..*;

sub cuisp-check ($cuisp where *.chars == 9) {
    my ($code, $chk) = $cuisp.comb(8);
    my $sum = [+] $code.comb.kv.map: { [+] (($^k % 2 + 1) * %chr{$^v}).&divmod(10) };
    so (10 - $sum mod 10) mod 10 eq $chk;
}

# TESTING
say "$_: ", $_.&cuisp-check for <
037833100
17275R102
38259P508
594918104
68389X106
68389X105
>
Output:
037833100: True
17275R102: True
38259P508: True
594918104: True
68389X106: False
68389X105: True

REXX

idiomatic

/*REXX program validates that the  last digit (the check digit)  of a  CUSIP  is valid. */
@.=
parse arg @.1 .
if @.1=='' | @.1==","  then do;   @.1= 037833100       /* Apple Incorporated            */
                                  @.2= 17275R102       /* Cisco Systems                 */
                                  @.3= 38259P508       /* Google Incorporated           */
                                  @.4= 594918104       /* Microsoft Corporation         */
                                  @.5= 68389X106       /* Oracle Corporation (incorrect)*/
                                  @.6= 68389X105       /* Oracle Corporation            */
                            end

     do j=1  while @.j\='';   chkDig=CUSIPchk(@.j)     /*calculate check digit from func*/
     OK=word("isn't is", 1 + (chkDig==right(@.j,1) ) ) /*validate  check digit with func*/
     say 'CUSIP '    @.j    right(OK, 6)     "valid."  /*display the CUSIP and validity.*/
     end   /*j*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
CUSIPchk: procedure;  arg x 9;  $=0;                     abc= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                                       do k=1  for 8
                                       y=substr(x, k, 1)
                                          select
                                          when datatype(y,'W')  then #=y
                                          when datatype(y,'U')  then #=pos(y, abc) + 9
                                          when          y=='*'  then #=36
                                          when          y=='@'  then #=37
                                          when          y=='#'  then #=38
                                          otherwise  return 0       /*invalid character.*/
                                          end   /*select*/
                                       if k//2==0  then #=#+#       /*K even?  Double it*/
                                       $=$ + #%10 + #//10
                                       end      /*k*/
           return (10- $//10) // 10

output   when using the default input:

CUSPID  037833100     is valid.
CUSPID  17275R102     is valid.
CUSPID  38259P508     is valid.
CUSPID  594918104     is valid.
CUSPID  68389X106  isn't valid.
CUSPID  68389X105     is valid.

conciser function

/*REXX program validates that the  last digit (the check digit)  of a  CUSIP  is valid. */
@.=
parse arg @.1 .
if @.1=='' | @.1==","  then do;   @.1= 037833100       /* Apple Incorporated            */
                                  @.2= 17275R102       /* Cisco Systems                 */
                                  @.3= 38259P508       /* Google Incorporated           */
                                  @.4= 594918104       /* Microsoft Corporation         */
                                  @.5= 68389X106       /* Oracle Corporation (incorrect)*/
                                  @.6= 68389X105       /* Oracle Corporation            */
                            end

     do j=1  while @.j\='';   chkDig=CUSIPchk(@.j)     /*calculate check digit from func*/
     OK=word("isn't is", 1 + (chkDig==right(@.j,1) ) ) /*validate  check digit with func*/
     say 'CUSIP '    @.j    right(OK, 6)     "valid."  /*display the CUSIP and validity.*/
     end   /*j*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
CUSIPchk: procedure; arg x 9;  $=0;         abc= '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#'
                                      /* [↓]  if  Y  isn' found,  then POS returns zero.*/
                                    do k=1  for 8;   y=substr(x,k,1) /*get a character. */
                                    #=pos(y, abc) - 1                /*get its position.*/
                                    if #   == -1  then return 0      /*invalid character*/
                                    if k//2==  0  then #=#+#         /*K even? double it*/
                                    $=$ + #%10 + #//10
                                    end      /*k*/
          return (10-$//10) // 10

output   is the same as the idiomatic REXX version.

Ring

# Project : CUSIP

inputstr = list(6)
inputstr[1] = "037833100"
inputstr[2] = "17275R102"
inputstr[3] = "38259P508"
inputstr[4] = "594918104"
inputstr[5] = "68389X106"
inputstr[6] = "68389X105"
for n = 1 to len(inputstr)
     cusip(inputstr[n])
next

func cusip(inputstr) 
        if len(inputstr) != 9
            see " length is incorrect, invalid cusip"
            return
        ok
        v = 0
        sum = 0
        for i = 1 to 8
             flag = 0
             x = ascii(inputstr[i])
             if x >= ascii("0") and x <= ascii("9")
                v = x - ascii("0")
                flag = 1
             ok
             if x >= ascii("A") and x <= ascii("Z")
                v = x - 55
                flag = 1
             ok
             if x = ascii("*")
                v= 36
                flag = 1
             ok
             if x = ascii("@")
                v = 37
                flag = 1
             ok
             if x = ascii("#")
                v = 38
                flag = 1
             ok
             if flag = 0 
                  see " found a invalid character, invalid cusip" + nl
             ok
             if (i % 2) = 0 
                 v = v * 2
             ok
             sum = sum + floor(v / 10) + v % 10
        next 
        sum = (10 - (sum % 10)) % 10
        if sum = (ascii(inputstr[9]) - ascii("0"))
           see inputstr + " is valid" + nl
        else
           see inputstr + " is invalid" + nl
        ok

Output:

037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
68389X105 is valid

RPL

Works with: Halcyon Calc version 4.2.7
RPL code Comment
≪ 
   SWAP ROT DUP2 ≤ OVER 5 ROLL ≤ AND 
   SWAP NUM ROT NUM - 1 + 0 IFTE
≫ 'BTWEEN' STO

≪  
   0
   1 8 FOR j
      OVER j DUP SUB → c
      ≪  IF c "0" "9" BTWEEN
         THEN LAST 1 - 
         ELSE IF c "A" "Z" BTWEEN
              THEN LAST 
              9 + 
              ELSE IF "*@#" c POS 
                   THEN LAST 35 + 
         END END END
         j 2 MOD SWAP DUP DUP + IFTE
         10 / LAST MOD SWAP IP + +
      ≫ NEXT
  10 SWAP 10 MOD - 10 MOD
  SWAP 9 DUP SUB STR→ ==
≫ 'CUSIP?' STO
BTWEEN ( "char" "from" "to"  -- pos )
evaluate "from" ≤ "char ≤ "to"
if yes, return relative position from "from"


CUSIP? ( "CUSIP"  -- boolean )
  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...)
        v := p + 9
     else if c = "*", "@", "#"  then
        v := 36, 37, 38

     if i is even then v := v × 2
     sum := sum + int ( v div 10 ) + v mod 10
  repeat
get (10 - (sum mod 10)) mod 10
return true if equal to 9th digit

Input:
 ≪ { "037833100" "17275R102" "38259P508" "594918104" "68389X106" "68389X105" } → tests
   ≪ {} 1 tests SIZE FOR n
        tests n GET n CUSIP? "Yes" "No" IFTE + NEXT 
 ≫ ≫ EVAL
Output:
1: { "Yes" "Yes" "Yes" "Yes" "No" "Yes" }

Ruby

Following pseudocode

#!/usr/bin/env ruby

def check_cusip(cusip)
  abort('CUSIP must be 9 characters') if cusip.size != 9

  sum = 0
  cusip.split('').each_with_index do |char, i|
    next if i == cusip.size - 1
    case
    when char.scan(/\D/).empty?
      v = char.to_i
    when char.scan(/\D/).any?
      pos = char.upcase.ord - 'A'.ord + 1
      v = pos + 9
    when char == '*'
      v = 36
    when char == '@'
      v = 37
    when char == '#'
      v = 38
    end

    v *= 2 unless (i % 2).zero?
    sum += (v/10).to_i + (v % 10)
  end

  check = (10 - (sum % 10)) % 10
  return 'VALID' if check.to_s == cusip.split('').last
  'INVALID'
end

CUSIPs = %w[
  037833100 17275R102 38259P508 594918104 68389X106 68389X105
]

CUSIPs.each do |cusip|
  puts "#{cusip}: #{check_cusip(cusip)}"
end

Output:

037833100: VALID
17275R102: VALID
38259P508: VALID
594918104: VALID
68389X106: INVALID
68389X105: VALID

More concise

Since it uses methods like chain, to_h, sum, and infinite Range syntax (0..), this needs a Ruby version > 2.5

TABLE = ("0".."9").chain("A".."Z", %w(* @ #)).zip(0..).to_h

def valid_CUSIP?(str)
  sum = str[0..-2].chars.each_slice(2).sum do |c1,c2|
    TABLE[c1].divmod(10).sum + (TABLE[c2]*2).divmod(10).sum
  end
  str[-1].to_i == (10 - (sum % 10)) % 10
end

CUSIPs = %w(037833100 17275R102 38259P508 594918104 68389X106 68389X105)
CUSIPs.each{|cusip| puts "#{cusip}: #{valid_CUSIP? cusip}"}

Rust

fn cusip_check(cusip: &str) -> bool {
    if cusip.len() != 9 {
        return false;
    }

    let mut v = 0;
    let capital_cusip = cusip.to_uppercase();
    let char_indices = capital_cusip.as_str().char_indices().take(7);

    let total = char_indices.fold(0, |total, (i, c)| {
        v = match c {
            '*' => 36,
            '@' => 37,
            '#' => 38,
            _ if c.is_digit(10) => c.to_digit(10).unwrap() as u8,
            _ if c.is_alphabetic() => (c as u8) - b'A' + 1 + 9,
            _ => v,
        };

        if i % 2 != 0 {
            v *= 2
        }
        total + (v / 10) + v % 10
    });

    let check = (10 - (total % 10)) % 10;
    (check.to_string().chars().nth(0).unwrap()) == cusip.chars().nth(cusip.len() - 1).unwrap()
}

fn main() {
    let codes = [
        "037833100",
        "17275R102",
        "38259P508",
        "594918104",
        "68389X106",
        "68389X105",
    ];
    for code in &codes {
        println!("{} -> {}", code, cusip_check(code))
    }
}

Output:

037833100 -> True
17275R102 -> True
38259P508 -> True
594918104 -> True
68389X106 -> False
68389X105 -> True

Scala

Output:

See it running in your browser by ScalaFiddle (JavaScript, non JVM) or by Scastie (JVM).

object Cusip extends App {

  val candidates = Seq("037833100", "17275R102", "38259P508", "594918104", "68389X106", "68389X105")

  for (candidate <- candidates)
    printf(f"$candidate%s -> ${if (isCusip(candidate)) "correct" else "incorrect"}%s%n")

  private def isCusip(s: String): Boolean = {
    if (s.length != 9) false
    else {
      var sum = 0
      for (i <- 0 until 7) {
        val c = s(i)
        var v = 0
        if (c >= '0' && c <= '9') v = c - 48
        else if (c >= 'A' && c <= 'Z') v = c - 55 // lower case letters apparently invalid
        else if (c == '*') v = 36
        else if (c == '@') v = 37
        else if (c == '#') v = 38
        else return false
        if (i % 2 == 1) v *= 2 // check if odd as using 0-based indexing
        sum += v / 10 + v % 10
      }
      s(8) - 48 == (10 - (sum % 10)) % 10
    }
  }

}

SNOBOL4

#!/usr/local/bin/snobol4 -r
*  cusip.sno
*   -- Committee on Uniform Security Identification Procedures
*  -r : read data placed after the end label.
*  Verify check digit and size of cusip code.

     define("cusipt()i")                  :(cusipt_end)
cusipt
     chars = &digits &ucase "*@#"
     cusipt = table()
     i = 0
cusipt_1
     chars pos(i) len(1) . c              :f(return)
     cusipt[c] = i
     i = i + 1                            :(cusipt_1)
cusipt_end

     define("check_cusip(line)c,i")       :(check_cusip_end)
check_cusip
     eq(size(line), 9)                    :f(freturn)
     check_cusip = 0
     i = 0
check_cusip_1
     line pos(i) len(1) . c
     value = t[c]
     value = eq(remdr(i, 2), 1) t[c] * 2
     check_cusip = check_cusip + (value / 10) + remdr(value, 10)
     i = lt(i, 7) i + 1                   :s(check_cusip_1)
     check_cusip = remdr(10 - remdr(check_cusip, 10), 10)
     eq(substr(line, 9, 1), check_cusip)  :s(return)f(freturn)
check_cusip_end

*** main ***
     t = cusipt()

read line = input                         :f(end)
     check_cusip(line)                    :f(bad_cusip)
     output = line " valid."              :(read)
bad_cusip
     output =  line " not valid."         :(read)
end
037833100
17275R102
38259P508
594918104
68389X106
68389X105
68389X10
68389X1059
68389x105
Output:
037833100 valid.
17275R102 valid.
38259P508 valid.
594918104 valid.
68389X106 not valid.
68389X105 valid.
68389X10 not valid.
68389X1059 not valid.
68389x105 not valid.

Swift

struct CUSIP {
  var value: String

  private static let alphabet = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ")

  init?(value: String) {
    if value.count == 9 && String(value.last!) == CUSIP.checkDigit(cusipString: String(value.dropLast())) {
      self.value = value
    } else if value.count == 8, let checkDigit = CUSIP.checkDigit(cusipString: value) {
      self.value = value + checkDigit
    } else {
      return nil
    }
  }

  static func checkDigit(cusipString: String) -> String? {
    guard cusipString.count == 8, cusipString.allSatisfy({ $0.isASCII }) else {
      return nil
    }

    let sum = cusipString.uppercased().enumerated().reduce(0, {sum, pair in
      let (i, char) = pair
      var v: Int

      switch char {
      case "*":
        v = 36
      case "@":
        v = 37
      case "#":
        v = 38
      case _ where char.isNumber:
        v = char.wholeNumberValue!
      case _:
        v = Int(char.asciiValue! - 65) + 10
      }

      if i & 1 == 1 {
        v *= 2
      }

      return sum + (v / 10) + (v % 10)
    })

    return String((10 - (sum % 10)) % 10)
  }
}

let testCases = [
  "037833100",
  "17275R102",
  "38259P508",
  "594918104",
  "68389X106",
  "68389X105"
]

for potentialCUSIP in testCases {
  print("\(potentialCUSIP) -> ", terminator: "")

  switch CUSIP(value: potentialCUSIP) {
  case nil:
    print("Invalid")
  case _:
    print("Valid")
  }
}
Output:
037833100 -> Valid
17275R102 -> Valid
38259P508 -> Valid
594918104 -> Valid
68389X106 -> Invalid
68389X105 -> Valid

Tcl

Direct translation of pseudocode

proc ordinal-of-alpha {c} {                     ;#  returns ordinal position of c in the alphabet (A=1, B=2...)
    lsearch {_ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} [string toupper $c]
}

proc Cusip-Check-Digit {cusip} {                ;# algorithm Cusip-Check-Digit(cusip) is
    if {[string length $cusip] != 8} {          ;#    Input: an 8-character CUSIP
        return false
    }
    
    set sum 0                                   ;#    sum := 0
    for {set i 1} {$i <= 8} {incr i} {          ;#    for 1 ≤ i ≤ 8 do
        set c [string index $cusip $i-1]        ;#       c := the ith character of cusip
        if {[string is digit $c]} {             ;#       if c is a digit then
            set v $c                            ;#          v := numeric value of the digit c
        } elseif {[string is alpha $c]} {       ;#       else if c is a letter then
            set p [ordinal-of-alpha $c]         ;#          p := ordinal position of c in the alphabet (A=1, B=2...)
            set v [expr {$p + 9}]               ;#          v := p + 9
        } elseif {$c eq "*"} {                  ;#       else if c = "*" then
            set v 36                            ;#          v := 36
        } elseif {$c eq "@"} {                  ;#       else if c = "@" then
            set v 37                            ;#          v := 37
        } elseif {$c eq "#"} {                  ;#       else if c = "#" then
            set v 38                            ;#          v := 38
        }                                       ;#       end if
        if {$i % 2 == 0} {                      ;#       if i is even then
            set v [expr {$v * 2}]               ;#          v := v × 2
        }                                       ;#       end if

        incr sum [expr {$v / 10 + $v % 10}]     ;#       sum := sum + int ( v div 10 ) + v mod 10
    }                                           ;#    repeat

    expr {(10 - ($sum % 10)) % 10}              ;#    return (10 - (sum mod 10)) mod 10
}
proc check-cusip {cusip} {
    set last  [string index $cusip end]
    set cusip [string range $cusip 0 end-1]
    expr {$last eq [Cusip-Check-Digit $cusip]}
}

More idiomatic Tcl

proc check-cusip {code} {
    if {[string length $code] != 9} {
        return false
    }
    set alphabet 0123456789abcdefghijklmnopqrstuvwxyz@#
    set code [split [string tolower $code] ""]
    foreach char $code idx {1 2 3 4 5 6 7 8 9} {
        set v [string first $char $alphabet]
        if {$v == -1} {return false}
        if {$idx % 2 == 0} {
            incr v $v
        }
        set v [::tcl::mathop::+ {*}[split $v ""]]
        incr sum $v
    }
    expr {$sum % 10 == 0}
}

Common test harness

proc test {} {
    foreach {cusip name} {
        037833100       "Apple Incorporated"
        17275R102       "Cisco Systems"
        38259P508       "Google Incorporated"
        594918104       "Microsoft Corporation"
        68389X106       "Oracle Corporation   (incorrect)"
        68389X105       "Oracle Corporation"
    } {
        puts [format %-40s%s $name [expr {[check-cusip $cusip] ? "valid" : "invalid"}]]
        puts [format %-40s%s $name [expr {[cusip-check $cusip] ? "valid" : "invalid"}]]
    }
}
test

Output

Output:
Apple Incorporated                      valid
Cisco Systems                           valid
Google Incorporated                     valid
Microsoft Corporation                   valid
Oracle Corporation   (incorrect)        invalid
Oracle Corporation                      valid

V (Vlang)

Translation of: Go
fn is_cusip(s string) bool {
    if s.len != 9 { return false }
    mut sum := 0
    for i in 0..8 {
        c := s[i]
        mut v :=0
        match true {
            c >= '0'[0] && c <= '9'[0] {
                v = c - 48
			}
            c >= 'A'[0] && c <= 'Z'[0] {
                v = c - 55
			}
            c == '*'[0] {
                v = 36
			}
            c == '@'[0] {
                v = 37
			}
            c == '#'[0] {
                v = 38
			}
            else {
                return false
			}
        }
        if i % 2 == 1 { v *= 2 }  // check if odd as using 0-based indexing
        sum += v/10 + v%10
    }
    return int(s[8]) - 48 == (10 - (sum%10)) % 10
}
 
fn main() {
    candidates := [
        "037833100",
        "17275R102",
        "38259P508",
        "594918104",
        "68389X106",
        "68389X105",
	]
 
    for candidate in candidates {
        mut b :=' '
        if is_cusip(candidate) {
            b = "correct"
        } else {
            b = "incorrect"
        }
        println("$candidate -> $b")
    }
}
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

Wren

Translation of: Go
var isCusip = Fn.new { |s|
    if (s.count != 9) return false
    var sum = 0
    for (i in 0..7) {
        var c = s[i].bytes[0]
        var v
        if (c >= 48 && c <= 57) { // '0' to '9'
            v = c - 48
        } else if (c >= 65 && c <= 90) { // 'A' to 'Z'
            v = c - 55
        } else if (s[i] == "*") {
            v = 36
        } else if (s[i] == "@") {
            v = 37
        } else if (s[i] == "#") {
            v = 38
        } else {
            return false
        }
        if (i%2 == 1) v = v * 2 // check if odd as using 0-based indexing
        sum = sum + (v/10).floor + v%10
    }
    return s[8].bytes[0] - 48 == (10 - (sum%10)) % 10
}

var candidates = [
    "037833100",
    "17275R102",
    "38259P508",
    "594918104",
    "68389X106",
    "68389X105"
]
for (candidate in candidates) {
    var b = (isCusip.call(candidate)) ? "correct" : "incorrect"
    System.print("%(candidate) -> %(b)")
}
Output:
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct

XPL0

string 0;               \use zero-terminated strings

func    Valid(Cusip);   \Return 'true' if valid CUSIP code
char    Cusip;
int     Sum, I, C, V;
[Sum:= 0;
for I:= 0 to 8-1 do
        [C:= Cusip(I);
        ChOut(0, C);
        case of
          C>=^0 & C<=^9: V:= C-^0;
          C>=^A & C<=^Z: V:= C-^A+10;
          C=^*: V:=36;
          C=^@: V:=37;
          C=^#: V:=38
        other V:= -1;
        if I&1 then V:= V*2;
        Sum:= Sum + V/10 + rem(0);
        ];
C:= Cusip(I);
ChOut(0, C);
V:= rem( (10-rem(Sum/10)) / 10 );
return V = C-^0;
];

int Cusip, N;
[Cusip:= ["037833100",
          "17275R102",
          "38259P508",
          "594918104",
          "68389X106",
          "68389X105"];
for N:= 0 to 6-1 do
        [Text(0, if Valid(Cusip(N))
                then " is valid"
                else " is invalid");
        CrLf(0);
        ];
]
Output:
037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
68389X105 is valid

Zig

const std = @import("std");
const print = std.debug.print;

pub fn CusipCheckDigit(cusip: *const [9:0]u8) bool {
    var i: usize = 0;
    var sum: i32 = 0;
    while (i < 8) {
        const c = cusip[i];
        var v: i32 = undefined;
        if (c <= '9' and c >= '0') {
            v = c - 48;
        }
        else if (c <= 'Z' and c >= 'A') {
            v = c - 55;
        }
        else if (c == '*') {
            v = 36;
        }
        else if (c == '@') {
            v = 37;
        }
        else if (c == '#') {
            v = 38;
        }
        else {
            return false;
        }
        if (i % 2 == 1) {
            v *= 2;
        }
        sum = sum + @divFloor(v, 10) + @mod(v, 10);
        i += 1;
    }
    return (cusip[8] - 48 == @mod((10 - @mod(sum, 10)), 10));
}

pub fn main() void {
    const cusips = [_]*const [9:0]u8 {
        "037833100",
        "17275R102",
        "38259P508",
        "594918104",
        "68389X106",
        "68389X105"
    };
    for (cusips) |cusip| {
        print("{s} -> {}\n", .{cusip, CusipCheckDigit(cusip)});
    }
}

zkl

fcn cusipCheckDigit(cusip){
   var [const] vs=[0..9].chain(["A".."Z"],T("*","@","#")).pump(String);
   try{
      sum:=Walker.cycle(1,2).zipWith(fcn(n,c){ v:=vs.index(c)*n; v/10 + v%10 },
           cusip[0,8]).reduce('+);
      ((10 - sum%10)%10 == cusip[8].toInt()) and cusip.len()==9
   }catch{ False }
}
foreach cusip in (T("037833100", "17275R102",
		    "38259P508", "594918104", "68389X106", "68389X105")){
   println(cusip,": ",cusipCheckDigit(cusip));      
}
Output:
037833100: True
17275R102: True
38259P508: True
594918104: True
68389X106: False
68389X105: True