CUSIP: Difference between revisions

Content deleted Content added
Created page with "{{draft task|Checksums}} {{wikipedia}} <br/> A CUSIP is a nine-character alphanumeric code that identifies a North American financial security for the purposes of facilitating..."
 
Langurmonkey (talk | contribs)
 
(187 intermediate revisions by 66 users not shown)
Line 1:
{{draft task|Checksums}}
{{wikipedia}}
<br/>
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.
 
A &nbsp; '''CUSIP''' &nbsp; 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.
The task here is to ensure the last digit (i.e. check digit) of the CUSIP code is correct, against the following codes.
 
* Apple Inc.: 037833100
* Cisco Systems: 17275R102
* Google Inc.: 38259P508
* Microsoft Corporation: 594918104
* Oracle Corporation (Incorrect): 68389X106
* Oracle Corporation: 68389X105
<br/>
;Example pseudo-code below.
 
;Task:
<lang>algorithm Cusip-Check-Digit(cusip) is
Ensure the last digit &nbsp; (i.e., the &nbsp; ''check digit'') &nbsp; of the '''CUSIP''' code (the 1<sup>st</sup> column) is correct, against the following:
* &nbsp; 037833100 &nbsp; &nbsp; &nbsp; Apple Incorporated
* &nbsp; 17275R102 &nbsp; &nbsp; &nbsp; Cisco Systems
* &nbsp; 38259P508 &nbsp; &nbsp; &nbsp; Google Incorporated
* &nbsp; 594918104 &nbsp; &nbsp; &nbsp; Microsoft Corporation
* &nbsp; 68389X106 &nbsp; &nbsp; &nbsp; Oracle Corporation &nbsp; (''incorrect'')
* &nbsp; 68389X105 &nbsp; &nbsp; &nbsp; Oracle Corporation
 
 
;Example pseudo-code below.
<syntaxhighlight lang=text>algorithm Cusip-Check-Digit(cusip) is
Input: an 8-character CUSIP
 
Line 41 ⟶ 43:
return (10 - (sum mod 10)) mod 10
end function</langsyntaxhighlight>
 
;See alsorelated tasks:
* [[SEDOLs|SEDOL]]
* [[Validate_International_Securities_Identification_Number|ISIN]]
<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}}==
<syntaxhighlight lang=360asm>* 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</syntaxhighlight>
{{out}}
<pre>
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
</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>
 
=={{header|Ada}}==
<syntaxhighlight lang=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;</syntaxhighlight>
{{Out}}
<pre>037833100: valid
17275R102: valid
38259P508: valid
594918104: valid
68389X106: not valid
68389X105: valid
</pre>
 
=={{header|ALGOL 68}}==
<syntaxhighlight lang=algol68>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</syntaxhighlight>
{{out}}
<pre>
037833100 valid
17275R102 valid
38259P508 valid
594918104 valid
68389X106 invalid
68389X105 valid
</pre>
 
=={{header|ALGOL W}}==
Based on Algol 68
<syntaxhighlight lang=algolw>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.</syntaxhighlight>
{{out}}
<pre>
037833100 valid
17275R102 valid
38259P508 valid
594918104 valid
68389X106 invalid
68389X105 valid
</pre>
 
=={{header|AppleScript}}==
<syntaxhighlight lang=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</syntaxhighlight>
{{Out}}
<pre>037833100 -> true
17275R102 -> true
38259P508 -> true
594918104 -> true
68389X106 -> false
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}}==
<syntaxhighlight lang=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])
}</syntaxhighlight>
Examples:<syntaxhighlight lang=AutoHotkey>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</syntaxhighlight>
{{out}}
<pre>Cusip Valid
037833100 1
17275R102 1
38259P508 1
594918104 1
68389X106 0
68389X105 1</pre>
 
=={{header|AWK}}==
<syntaxhighlight lang=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)
}
</syntaxhighlight>
{{out}}
<pre>
037833100 1
17275R102 1
38259P508 1
594918104 1
68389X106 0
68389X105 1
</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}}==
Reads CUSIP strings from a file and prints results to console, usage printed on incorrect invocation.
<syntaxhighlight lang=C>
#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;
}
</syntaxhighlight>
Input file :
<pre>
6
037833100
17275R102
38259P508
594918104
68389X106
68389X105
</pre>
Invocation and output :
<pre>
C:\rosettaCode>cusipCheck.exe cusipData.txt
CUSIP Verdict
-------------------
037833100 : Valid
17275R102 : Valid
38259P508 : Valid
594918104 : Valid
68389X106 : Invalid
68389X105 : Valid
</pre>
 
=={{header|C sharp|C#}}==
{{trans|Java}}
<syntaxhighlight lang=csharp>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");
}
}
}
}</syntaxhighlight>
{{out}}
<pre>037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct</pre>
 
=={{header|C++}}==
{{trans|C#}}
<syntaxhighlight lang=cpp>#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;
}</syntaxhighlight>
{{out}}
<pre>037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct</pre>
 
=={{header|Caché ObjectScript}}==
 
<langsyntaxhighlight lang=cos>Class Utils.Check [ Abstract ]
{
 
Line 67 ⟶ 1,344:
}
 
}</langsyntaxhighlight>
{{out|Examples}}
<pre>USER>For { Read s Quit:s="" Write ": "_##class(Utils.Check).CUSIP(s), ! }
Line 78 ⟶ 1,355:
 
USER></pre>
 
=={{header|Clojure}}==
<syntaxhighlight lang=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"))))
</syntaxhighlight>
 
{{out}}
<pre>
(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
</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}}==
<syntaxhighlight lang=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))))</syntaxhighlight>
{{out}}
<pre>037833100: T
17275R102: T
38259P508: T
594918104: T
68389X106: NIL
68389X105: T</pre>
 
=={{header|D}}==
<syntaxhighlight lang=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`</syntaxhighlight>
 
{{out}}
<pre>CUSIP Verdict
037833100 : Valid
17275R102 : Valid
38259P508 : Valid
594918104 : Valid
68389X106 : Invalid
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}}==
 
{{trans|Go}}
 
<syntaxhighlight lang=dyalect>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)")
}</syntaxhighlight>
 
{{out}}
 
<pre>037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
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}}==
===LAMBDA===
 
Binding the names ISCUSIP and CUSIPMAP to the following lambda expressions in the Name Manager of the Excel WorkBook:
 
(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,
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}</syntaxhighlight>
 
and also assuming the following generic bindings in the Name Manager for the WorkBook:
 
<syntaxhighlight lang=lisp>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)
)
)</syntaxhighlight>
 
{{Out}}
{| class="wikitable"
|-
|||style="text-align:right; font-family:serif; font-style:italic; font-size:120%;"|fx
! colspan="2" style="text-align:left; vertical-align: bottom; font-family:Arial, Helvetica, sans-serif !important;"|=ISCUSIP(A2)
|- style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff;"
|
| A
| B
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 1
| style="text-align:right; font-weight:bold" | Strings
| style="font-weight:bold" | CUSIP verdicts
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 2
| style="text-align:right; font-weight:bold" | 037833100
| style="background-color:#cbcefb;" | TRUE
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 3
| style="text-align:right; font-weight:bold" | 17275R102
| TRUE
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 4
| style="text-align:right; font-weight:bold" | 38259P508
| TRUE
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 5
| style="text-align:right; font-weight:bold" | 594918104
| TRUE
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 6
| style="text-align:right; font-weight:bold" | 68389X106
| FALSE
|- style="text-align:right;"
| style="text-align:center; font-family:Arial, Helvetica, sans-serif !important; background-color:#000000; color:#ffffff" | 7
| style="text-align:right; font-weight:bold" | 68389X105
| TRUE
|}
 
=={{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}}==
<syntaxhighlight lang=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</syntaxhighlight>
{{out}}
<pre>
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct
</pre>
 
=={{header|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. <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.
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</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.
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!
 
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="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
</syntaxhighlight>
{{output}}
<pre>
0378331009: Invalid length
037833100: Valid
17275R102: Valid
38259P508: Valid
594918104: Valid
68389X106: Invalid
68389X105: Valid
683&9X105: Invalid character: &
</pre>
 
=={{header|Go}}==
<syntaxhighlight lang=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)
}
}
</syntaxhighlight>
 
{{out}}
<pre>
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct
</pre>
 
=={{header|Groovy}}==
{{trans|Java}}
<syntaxhighlight lang=groovy>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")
}
}
}</syntaxhighlight>
{{out}}
<pre>037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct</pre>
 
=={{header|Haskell}}==
<syntaxhighlight lang=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)</syntaxhighlight>
 
{{out}}
<pre>037833100: Valid
17275R102: Valid
38259P508: Valid
594918104: Valid
68389X106: BadCheck
68389X105: Valid
</pre>
 
Or, picking some other possibilities from Haskell's rich libraries:
<syntaxhighlight lang=Haskell>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"
]</syntaxhighlight>
{{Out}}
<pre>("037833100",True)
("17275R102",True)
("38259P508",True)
("594918104",True)
("68389X106",False)
("68389X105",True)</pre>
 
=={{header|Icon}} and {{header|Unicon}}==
<syntaxhighlight lang=Icon># 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</syntaxhighlight>
 
{{out}}<pre>037833100 : valid.
17275R102 : valid.
38259P508 : valid.
594918104 : valid.
68389X106 : not valid.
68389X105 : valid.
</pre>
 
=={{header|J}}==
One-liner:
<syntaxhighlight lang=j> ccd =. 10 | 10 - 10 | [: +/ [: , 10 (#.^:_1) (8 $ 1 2) * '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#' i. ]
ccd '68389X10'
5</syntaxhighlight>
 
More verbose version that checks for correct input:
<syntaxhighlight lang=j> 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@}:</syntaxhighlight>
 
Examples:
<syntaxhighlight lang=j> addCUSIPcheckdigit '68389X10'
68389X105
verifyCUSIPcheckdigit '68389X106'
0
verifyCUSIPcheckdigit '68389X105'
1
samples =: '037833100', '17275R102', '38259P508', '594918104', '68389X106',: '68389X105'
samples ; verifyCUSIPcheckdigit"1 samples
┌─────────┬─┐
│037833100│1│
│17275R102│1│
│38259P508│1│
│594918104│1│
│68389X106│0│
│68389X105│1│
└─────────┴─┘</syntaxhighlight>
 
=={{header|Java}}==
{{trans|Kotlin}}
Uses Java 9
<syntaxhighlight lang=Java>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");
}
}
}</syntaxhighlight>
{{out}}
<pre>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
</pre>
 
=={{header|JavaScript}}==
<syntaxhighlight lang=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();
})();</syntaxhighlight>
{{Out}}
<pre>037833100 -> true
17275R102 -> true
38259P508 -> true
594918104 -> true
68389X106 -> false
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}}==
{{works with|Julia|0.6}}
 
<syntaxhighlight lang=julia>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</syntaxhighlight>
 
{{out}}
<pre>037833100 is correct.
17275R102 is correct.
38259P508 is correct.
594918104 is correct.
68389X106 is not correct.
68389X105 is correct.</pre>
 
=={{header|Kotlin}}==
<syntaxhighlight lang=scala>// 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"}")
}</syntaxhighlight>
 
{{out}}
<pre>
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct
</pre>
 
=={{header|langur}}==
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 {
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")
}
</syntaxhighlight>
 
Following the pseudo-code would look more like the following.
{{trans|Go}}
<syntaxhighlight lang=langur>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 {
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 = fw/037833100 17275R102 38259P508 594918104 68389X106 68389X105/
 
for c in candidates {
writeln c, ": ", if(isCusip(c): "good" ; "bad")
}
</syntaxhighlight>
 
{{out}}
<pre>037833100: good
17275R102: good
38259P508: good
594918104: good
68389X106: bad
68389X105: good</pre>
 
=={{header|Lua}}==
The checkDigit function is a line-for-line translation of the pseudo-code algorithm.
<syntaxhighlight lang=Lua>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</syntaxhighlight>
{{out}}
<pre>037833100: VALID
17275R102: VALID
38259P508: VALID
594918104: VALID
68389X106: INVALID
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}}==
<syntaxhighlight lang=modula2>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.</syntaxhighlight>
{{out}}
<pre>CUSIP Verdict
037833100 : Valid
17275R102 : Valid
38259P508 : Valid
594918104 : Valid
68389X106 : Invalid
68389X105 : Valid</pre>
 
=={{header|Nanoquery}}==
<syntaxhighlight lang=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</syntaxhighlight>
 
{{out}}
<pre>037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
68389X105 is valid</pre>
 
=={{header|Nim}}==
<syntaxhighlight lang=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()</syntaxhighlight>
 
{{out}}
<pre>037833100: Valid
17275R102: Valid
38259P508: Valid
594918104: Valid
68389X106: Invalid
68389X105: Valid
</pre>
 
=={{header|Objeck}}==
{{trans|Kotlin}}
<syntaxhighlight lang=Objeck>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();
};
};
}
}</syntaxhighlight>
 
Output:
<pre>
037833100 => correct
17275R102 => correct
38259P508 => correct
594918104 => correct
68389X106 => incorrect
68389X105 => correct
</pre>
 
=={{header|Perl}}==
 
<syntaxhighlight lang=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;</syntaxhighlight>
{{out}}
<pre>037833100 Apple Incorporated
17275R102 Cisco Systems
38259P508 Google Incorporated
594918104 Microsoft Corporation
68389X105 Oracle Corporation
68389X106 Oracle Corporation (incorrect)</pre>
 
=={{header|Phix}}==
<!--<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: #008080;">function</span> <span style="color: #000000;">CusipCheckDigit</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">cusip</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">v</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cch</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">cch</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">256</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">to</span> <span style="color: #008000;">'9'</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">cch</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'0'</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'A'</span> <span style="color: #008080;">to</span> <span style="color: #008000;">'Z'</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">cch</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">55</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">cch</span><span style="color: #0000FF;">[</span><span style="color: #008000;">'*'</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">36</span>
<span style="color: #000000;">cch</span><span style="color: #0000FF;">[</span><span style="color: #008000;">'@'</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">37</span>
<span style="color: #000000;">cch</span><span style="color: #0000FF;">[</span><span style="color: #008000;">'#'</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">38</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cusip</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">9</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'\0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cusip</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">8</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">cusip</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">v</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">cch</span><span style="color: #0000FF;">[</span><span style="color: #000000;">c</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">v</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">2</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">s</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">/</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)+</span><span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">cusip</span><span style="color: #0000FF;">[</span><span style="color: #000000;">9</span><span style="color: #0000FF;">]=</span><span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10</span><span style="color: #0000FF;">-</span><span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10</span><span style="color: #0000FF;">),</span><span style="color: #000000;">10</span><span style="color: #0000FF;">)+</span><span style="color: #008000;">'0'</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"037833100"</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- Apple Incorporated</span>
<span style="color: #008000;">"17275R102"</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- Cisco Systems</span>
<span style="color: #008000;">"38259P508"</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- Google Incorporated</span>
<span style="color: #008000;">"594918104"</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- Microsoft Corporation</span>
<span style="color: #008000;">"68389X106"</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- Oracle Corporation (incorrect)</span>
<span style="color: #008000;">"68389X105"</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- Oracle Corporation</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">ti</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</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>
<!--</syntaxhighlight>-->
{{out}}
<pre>
037833100 : valid
17275R102 : valid
38259P508 : valid
594918104 : valid
68389X106 : invalid
68389X105 : valid
</pre>
 
=={{header|PHP}}==
<syntaxhighlight lang=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";</syntaxhighlight>
{{out}}
<pre>
037833100 -> valid
17275R102 -> valid
38259P508 -> valid
594918104 -> valid
68389X106 -> invalid
68389X105 -> valid</pre>
 
=={{header|PicoLisp}}==
<syntaxhighlight lang=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" ) ) )</syntaxhighlight>
{{out}}
<pre>(T T T NIL T)</pre>
 
=={{header|PowerShell}}==
<syntaxhighlight lang=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] }
</syntaxhighlight>{{out}}<pre>
True
True
True
True
False
True
</pre>
 
=={{header|Python}}==
===Procedural===
Requires Python 3.6 for the string template literal in the print statement.
 
<syntaxhighlight lang=python>#!/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)}')
</syntaxhighlight>
Output:
<pre>037833100 -> True
17275R102 -> True
38259P508 -> True
594918104 -> True
68389X106 -> False
68389X105 -> True
</pre>
 
===Composition of pure functions===
{{Works with|Python|3.7}}
Composing a set of pure functions, including a number of general and reusable abstractions:
<syntaxhighlight lang=python>'''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()</syntaxhighlight>
{{Out}}
<pre>Test for validity as a CUSIP string:
 
'037833100' -> True
'17275R102' -> True
'38259P508' -> True
'594918104' -> True
'68389X106' -> False
'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}}==
 
<syntaxhighlight lang=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")))</syntaxhighlight>
 
no output indicates all tests passed.
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2017.01}}
 
<syntaxhighlight lang=raku line>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
></syntaxhighlight>
{{out}}
<pre>037833100: True
17275R102: True
38259P508: True
594918104: True
68389X106: False
68389X105: True</pre>
 
=={{header|REXX}}==
===idiomatic===
<syntaxhighlight lang=rexx>/*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</syntaxhighlight>
'''output''' &nbsp; when using the default input:
<pre>
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.
</pre>
 
===conciser function===
<syntaxhighlight lang=rexx>/*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</syntaxhighlight>
'''output''' &nbsp; is the same as the idiomatic REXX version. <br><br>
 
=={{header|Ring}}==
<syntaxhighlight lang=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
</syntaxhighlight>
Output:
<pre>
037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
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>
 
=={{header|Ruby}}==
===Following pseudocode===
<syntaxhighlight lang=ruby>
#!/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
 
</syntaxhighlight>
 
Output:
<pre>
037833100: VALID
17275R102: VALID
38259P508: VALID
594918104: VALID
68389X106: INVALID
68389X105: VALID
</pre>
===More concise===
Since it uses methods like chain, to_h, sum, and infinite Range syntax (0..), this needs a Ruby version > 2.5
<syntaxhighlight lang=Ruby>
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}"}
</syntaxhighlight>
 
=={{header|Rust}}==
 
<syntaxhighlight lang=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))
}
}</syntaxhighlight>
 
Output:
<pre>037833100 -> True
17275R102 -> True
38259P508 -> True
594918104 -> True
68389X106 -> False
68389X105 -> True
</pre>
 
=={{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)].
<syntaxhighlight lang=Scala>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
}
}
 
}</syntaxhighlight>
 
=={{header|SNOBOL4}}==
<syntaxhighlight lang=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</syntaxhighlight>
{{out}}
<pre>037833100 valid.
17275R102 valid.
38259P508 valid.
594918104 valid.
68389X106 not valid.
68389X105 valid.
68389X10 not valid.
68389X1059 not valid.
68389x105 not valid.</pre>
 
=={{header|Swift}}==
 
<syntaxhighlight lang=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")
}
}</syntaxhighlight>
 
{{out}}
 
<pre>037833100 -> Valid
17275R102 -> Valid
38259P508 -> Valid
594918104 -> Valid
68389X106 -> Invalid
68389X105 -> Valid</pre>
 
=={{header|Tcl}}==
=== Direct translation of pseudocode ===
<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]
}
 
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]}
}</syntaxhighlight>
 
=== More idiomatic Tcl ===
<syntaxhighlight lang=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}
}</syntaxhighlight>
 
=== Common test harness ===
<syntaxhighlight lang=Tcl>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</syntaxhighlight>
 
=== Output ===
{{out}}
<pre>Apple Incorporated valid
Cisco Systems valid
Google Incorporated valid
Microsoft Corporation valid
Oracle Corporation (incorrect) invalid
Oracle Corporation valid</pre>
 
=={{header|V (Vlang)}}==
{{trans|Go}}
<syntaxhighlight lang="v (vlang)">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")
}
}</syntaxhighlight>
 
{{out}}
<pre>
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct
</pre>
 
=={{header|Wren}}==
{{trans|Go}}
<syntaxhighlight lang="wren">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)")
}</syntaxhighlight>
 
{{out}}
<pre>
037833100 -> correct
17275R102 -> correct
38259P508 -> correct
594918104 -> correct
68389X106 -> incorrect
68389X105 -> correct
</pre>
 
=={{header|XPL0}}==
<syntaxhighlight lang=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);
];
]</syntaxhighlight>
 
{{out}}
<pre>
037833100 is valid
17275R102 is valid
38259P508 is valid
594918104 is valid
68389X106 is invalid
68389X105 is valid
</pre>
 
=={{header|Zig}}==
<syntaxhighlight lang=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)});
}
}
</syntaxhighlight>
 
=={{header|zkl}}==
<syntaxhighlight lang=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 }
}</syntaxhighlight>
<syntaxhighlight lang=zkl>foreach cusip in (T("037833100", "17275R102",
"38259P508", "594918104", "68389X106", "68389X105")){
println(cusip,": ",cusipCheckDigit(cusip));
}</syntaxhighlight>
{{out}}
<pre>
037833100: True
17275R102: True
38259P508: True
594918104: True
68389X106: False
68389X105: True
</pre>