Initial data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 72d218235f
commit f23f22d71c
199087 changed files with 3378941 additions and 0 deletions

3
Task/CUSIP/00-META.yaml Normal file
View file

@ -0,0 +1,3 @@
---
from: http://rosettacode.org/wiki/CUSIP
note: Checksums

49
Task/CUSIP/00-TASK.txt Normal file
View file

@ -0,0 +1,49 @@
<br/>
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.
;Task:
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
sum := 0
for 1 ≤ i ≤ 8 do
c := the ith character of cusip
if c is a digit then
v := numeric value of the digit c
else if c is a letter then
p := ordinal position of c in the alphabet (A=1, B=2...)
v := p + 9
else if c = "*" then
v := 36
else if c = "@" then
v := 37
else if' c = "#" then
v := 38
end if
if i is even then
v := v × 2
end if
sum := sum + int ( v div 10 ) + v mod 10
repeat
return (10 - (sum mod 10)) mod 10
end function</syntaxhighlight>
;See related tasks:
* [[SEDOLs|SEDOL]]
* [[Validate_International_Securities_Identification_Number|ISIN]]
<br>

36
Task/CUSIP/11l/cusip.11l Normal file
View file

@ -0,0 +1,36 @@
F cusip_check(=cusip)
I cusip.len != 9
X 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))

View file

@ -0,0 +1,81 @@
* 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

View file

@ -0,0 +1,49 @@
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

View file

@ -0,0 +1,35 @@
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.

41
Task/CUSIP/AWK/cusip.awk Normal file
View file

@ -0,0 +1,41 @@
# 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)
}

View file

@ -0,0 +1,61 @@
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

54
Task/CUSIP/Ada/cusip.ada Normal file
View file

@ -0,0 +1,54 @@
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;

View file

@ -0,0 +1,280 @@
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

View file

@ -0,0 +1,27 @@
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"]
]

View file

@ -0,0 +1,21 @@
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])
}

View file

@ -0,0 +1,14 @@
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

View file

@ -0,0 +1,35 @@
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")
$)

49
Task/CUSIP/C++/cusip.cpp Normal file
View file

@ -0,0 +1,49 @@
#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 - '@';
} else if (c = '*') {
v = 36;
} 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;
}

View file

@ -0,0 +1,48 @@
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");
}
}
}
}

53
Task/CUSIP/C/cusip.c Normal file
View file

@ -0,0 +1,53 @@
#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;
}

33
Task/CUSIP/CLU/cusip.clu Normal file
View file

@ -0,0 +1,33 @@
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

View file

@ -0,0 +1,46 @@
(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"))))

View file

@ -0,0 +1,23 @@
(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))))

99
Task/CUSIP/D/cusip.d Normal file
View file

@ -0,0 +1,99 @@
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`

View file

@ -0,0 +1,48 @@
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;

View file

@ -0,0 +1,38 @@
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)")
}

View file

@ -0,0 +1,39 @@
=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}

View file

@ -0,0 +1,31 @@
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)
)
)

View file

@ -0,0 +1,4 @@
// 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"))

View file

@ -0,0 +1,18 @@
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

View file

@ -0,0 +1,34 @@
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

View file

@ -0,0 +1,63 @@
' 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

View file

@ -0,0 +1,49 @@
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

50
Task/CUSIP/Go/cusip.go Normal file
View file

@ -0,0 +1,50 @@
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)
}
}

View file

@ -0,0 +1,40 @@
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")
}
}
}

View file

@ -0,0 +1,44 @@
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)

View file

@ -0,0 +1,37 @@
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"
]

View file

@ -0,0 +1,40 @@
# 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

3
Task/CUSIP/J/cusip-1.j Normal file
View file

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

10
Task/CUSIP/J/cusip-2.j Normal file
View file

@ -0,0 +1,10 @@
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@}:

16
Task/CUSIP/J/cusip-3.j Normal file
View file

@ -0,0 +1,16 @@
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│
└─────────┴─┘

View file

@ -0,0 +1,39 @@
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");
}
}
}

View file

@ -0,0 +1,429 @@
(() => {
'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();
})();

39
Task/CUSIP/Jq/cusip.jq Normal file
View file

@ -0,0 +1,39 @@
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)"

View file

@ -0,0 +1,33 @@
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

View file

@ -0,0 +1,33 @@
// 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"}")
}

View file

@ -0,0 +1,23 @@
val .isCusip = f(.s) {
if not isString(.s) or len(.s) != 9 {
return false
}
val .basechars = cp2s('0'..'9') ~ cp2s('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 x= 2
_for += .v \ 10 + .v rem 10
}
.s[9]-'0' == (10-(.sum rem 10)) rem 10
}
val .candidates = w/037833100 17275R102 38259P508 594918104 68389X106 68389X105/
for .c in .candidates {
writeln .c, ": ", if(.isCusip(.c): "good" ; "bad")
}

View file

@ -0,0 +1,37 @@
val .isCusip = f(.s) {
if not isString(.s) or len(.s) != 9 {
return false
}
val .sum = for[=0] .i of 8 {
val .c = .s[.i]
var .v = 0
given .c {
# for given, default op between conditions is "and"
# for switch, default op between conditions is "or"
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 x= 2
_for += .v \ 10 + .v rem 10
}
.s[9]-'0' == (10-(.sum rem 10)) rem 10
}
val .candidates = w/037833100 17275R102 38259P508 594918104 68389X106 68389X105/
for .c in .candidates {
writeln .c, ": ", if(.isCusip(.c): "good" ; "bad")
}

44
Task/CUSIP/Lua/cusip.lua Normal file
View file

@ -0,0 +1,44 @@
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

View file

@ -0,0 +1,23 @@
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"}

View file

@ -0,0 +1,76 @@
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.

View file

@ -0,0 +1,38 @@
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

41
Task/CUSIP/Nim/cusip.nim Normal file
View file

@ -0,0 +1,41 @@
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()

View file

@ -0,0 +1,58 @@
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();
};
};
}
}

39
Task/CUSIP/PHP/cusip.php Normal file
View file

@ -0,0 +1,39 @@
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";

27
Task/CUSIP/Perl/cusip.pl Normal file
View file

@ -0,0 +1,27 @@
$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;

View file

@ -0,0 +1,42 @@
(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>
<!--

View file

@ -0,0 +1,29 @@
(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" ) ) )

View file

@ -0,0 +1,48 @@
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] }

View file

@ -0,0 +1,42 @@
#!/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)}')

View file

@ -0,0 +1,160 @@
'''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()

View file

@ -0,0 +1,26 @@
[ -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

View file

@ -0,0 +1,32 @@
/*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

View file

@ -0,0 +1,26 @@
/*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

View file

@ -0,0 +1,37 @@
#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")))

View file

@ -0,0 +1,18 @@
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
>

View file

@ -0,0 +1,57 @@
# 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

View file

@ -0,0 +1,38 @@
#!/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

View file

@ -0,0 +1,11 @@
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}"}

View file

@ -0,0 +1,42 @@
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))
}
}

View file

@ -0,0 +1,50 @@
#!/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

View file

@ -0,0 +1,28 @@
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
}
}
}

View file

@ -0,0 +1,67 @@
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")
}
}

View file

@ -0,0 +1,38 @@
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]}
}

View file

@ -0,0 +1,17 @@
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}
}

View file

@ -0,0 +1,14 @@
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

View file

@ -0,0 +1,52 @@
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")
}
}

27
Task/CUSIP/VBA/cusip.vba Normal file
View file

@ -0,0 +1,27 @@
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

View file

@ -0,0 +1,48 @@
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

View file

@ -0,0 +1,37 @@
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)")
}

View file

@ -0,0 +1,39 @@
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);
];
]

View file

@ -0,0 +1,47 @@
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

49
Task/CUSIP/Zig/cusip.zig Normal file
View file

@ -0,0 +1,49 @@
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)});
}
}

View file

@ -0,0 +1,8 @@
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 }
}

View file

@ -0,0 +1,4 @@
foreach cusip in (T("037833100", "17275R102",
"38259P508", "594918104", "68389X106", "68389X105")){
println(cusip,": ",cusipCheckDigit(cusip));
}