Module Currency_Task {
      Locale 1033
      Font "Courier New"
      Form 80,32
      \\Decimal type
      [email protected]
      \\ Currency type
      hamburger_price=5.5#
      milkshakes=2#
      milkshake_price=2.86#
      tax_rate=0.0765#
      \\ Using Columns with variable width in console
      PrHeadLine("Item","price","quantity", "value")
      PrLine("hamburger",hamburger_price,hamburgers,hamburgers*hamburger_price)
      PrLine("milkshake", milkshake_price,milkshakes,milkshakes*milkshake_price)
      PrResults( "subtotal", hamburgers*hamburger_price+milkshakes*milkshake_price)
      PrResults("tax", (hamburgers*hamburger_price+milkshakes*milkshake_price)*tax_rate)
      \\ 1 is double by default we can use 1# or [email protected]
      PrResults("total", (hamburgers*hamburger_price+milkshakes*milkshake_price)*(tax_rate+1))

      \\ Using variables for partial calculations. They get type from expression result
      h_p_q=hamburgers*hamburger_price
      m_p_q=milkshakes*milkshake_price

      \\ Using format$ to prepare final strings
      Print format$("{0:15}{1:-8}{2:-25}{3:-25}","Item", "price", "quantity", "value")
      Print format$("{0:15}{1:2:-8}{2:0:-25}{3:2:-25}","hamburger",hamburger_price,hamburgers, h_p_q)
      Print format$("{0:15}{1:2:-8}{2:0:-25}{3:2:-25}","milkshake", milkshake_price,milkshakes,m_p_q)
      Print format$("{0:-48}{1:2:-25}","subtotal", h_p_q+m_p_q)
      Print format$("{0:-48}{1:2:-25}","tax", (h_p_q+m_p_q)*tax_rate)
      Print format$("{0:-48}{1:2:-25}","total", (h_p_q+m_p_q)*(tax_rate+1))
      \\ Another time to feed Document to export to clipboard
      Document Doc$=format$("{0:15}{1:-8}{2:-25}{3:-25}","Item", "price", "quantity", "value")+{
      }+format$("{0:15}{1:2:-8}{2:0:-25}{3:2:-25}","hamburger",hamburger_price,hamburgers, h_p_q)+{
      }+format$("{0:15}{1:2:-8}{2:0:-25}{3:2:-25}","milkshake", milkshake_price,milkshakes,m_p_q)+{
      }+format$("{0:-48}{1:2:-25}","subtotal", h_p_q+m_p_q)+{
      }+format$("{0:-48}{1:2:-25}","tax", (h_p_q+m_p_q)*tax_rate)+{
      }+format$("{0:-48}{1:2:-25}","total", (h_p_q+m_p_q)*(tax_rate+1))+{
      }
      clipboard Doc$
      \\ one line user function definition
      \\ x get type from passed value
      Def ExpressionType$(x)=Type$(X)
      \\ Check Expression final type
      Print ExpressionType$(hamburgers)="Decimal"
      Print ExpressionType$(milkshakes)="Currency"
      Print ExpressionType$(h_p_q)="Decimal"
      Print ExpressionType$(m_p_q)="Currency"
      Print ExpressionType$((h_p_q+m_p_q)*tax_rate)="Decimal"
      Print ExpressionType$((h_p_q+m_p_q)*(tax_rate+1))="Decimal"

      Sub PrHeadLine(a$,b$,c$,d$)
            Print Part  $(1,15),a$,$(3,8),b$, $(3,25),c$, $(3,25),d$
            Print
      End Sub
      Sub PrLine(a$,b,c,d)
            Print Part  $(1,15),a$,$("0.00"),$(3,8),b, $("0"),$(3,25),c,$("0.00"), $(3,25),d
            Print
      End Sub
      Sub PrResults(a$,b)
            Print Part  $(3,48),a$,$("0.00"),$(3,25),b
            Print
      End Sub
}
Currency_Task


Digits := 50;
tax := .0765;

burgersquantity := 4000000000000000;
burgersprice := 5.50;
burgerscost := burgersquantity * burgersprice;

milkshakesquantity := 2;
milkshakesprice := 2.86;
milkshakescost := milkshakesquantity * milkshakesprice;

total := burgerscost + milkshakescost;
printf("%.2f\n",total);

totaltax := total * tax;
printf("%.2f\n",totaltax);

totalprice := totaltax + total;
printf("%.2f\n",totalprice);


total = 4000000000000000 Rationalize[5.50] + 2 Rationalize[2.86];
AccountingForm[N[total, 20], {\[Infinity], 2}]
tax = total Rationalize[0.0765];
AccountingForm[N[tax, 20], {\[Infinity], 2}]
AccountingForm[N[total + tax, 20], {\[Infinity], 2}]


import strutils
import bignum

type Currency = Int

#---------------------------------------------------------------------------------------------------

func currency(units, subunits: int): Currency =
  ## Build a currency from units and subunits.
  ## Units may be negative. Subunits must be in range 0..99.
  if subunits notin 0..99:
    raise newException(ValueError, "wrong value for subunits")
  result = if units >= 0: newInt(units * 100 + subunits)
           else: newInt(subunits * 100 - subunits)

#---------------------------------------------------------------------------------------------------

func currency(value: string): Currency =
  ## Build a currency from a string.
  ## Negative values are allowed. At most two digits are allowed for subunits.

  const StartingChars = Digits + {'-'}
  if value.len == 0 or value[0] notin StartingChars:
    raise newException(ValueError, "wrong currency string")

  # process sign and units.
  var units = newInt(0)
  var subunits = 0
  let sign = if value[0] == '-': -1 else: 1
  var idx = if sign == 1: 0 else: 1
  while idx < value.len:
    if value[idx] notin Digits: break
    units = 10 * units + ord(value[idx]) - ord('0')
    inc idx

  # Process separator.
  if idx <= value.high:
    if value[idx] != '.':
      raise newException(ValueError, "expected a separator")
    inc idx

  # Process subunits.
  for _ in 0..1:
    let c = if idx >= value.len: '0' else: value[idx]
    if c notin Digits:
      raise newException(ValueError, "wrong value for subunits")
    subunits = 10 * subunits + ord(c) - ord('0')
    inc idx

  if idx <= value.high:
    raise newException(ValueError, "extra characters after subunits digits")

  result = sign * (units * 100 + subunits)

#---------------------------------------------------------------------------------------------------

func `//`(a, b: int): Rat =
  ## Create a rational value.
  newRat(a, b)

#---------------------------------------------------------------------------------------------------

func percentage(a: Currency; p: Rat): Currency =
  ## Compute a percentage on currency value "a".
  ## Returned value is rounded to nearest integer.

  (a * p.num * 10 div p.denom + 5) div 10

#---------------------------------------------------------------------------------------------------

func `$`(a: Currency): string =
  ## Build a string representation of a currency value.

  result = bignum.`$`(a div 100) & '.' & ($(a mod 100).toInt).align(2, '0')

#———————————————————————————————————————————————————————————————————————————————————————————————————

let hamburgers = currency(5, 50) * int 4_000_000_000_000_000
let milkshakes = currency("2.86") * 2
let rate = 765 // 10_000
let beforeTax = hamburgers + milkshakes
let tax = beforeTax.percentage(rate)
let total = beforeTax + tax

# Find the maximum length of numerical value representations.
let beforeTaxStr = $beforeTax
let taxStr = $tax
let totalStr = $total
let length = max([beforeTaxStr.len, taxStr.len, totalStr.len])

# Display the results.
echo "Total price before tax: ", beforeTaxStr.align(length)
echo "Tax:                    ", taxStr.align(length)
echo "Total with tax:         ", totalStr.align(length)


#require "bignum" ;;

let p1 = Bignum.((of_string "4000000000000000") * (of_float_decimal 5.50)) ;;
let p2 = Bignum.((of_int 2) * (of_float_decimal 2.86)) ;;

let r1 = Bignum.(p1 + p2) ;;
let r2 = Bignum.(r1 * (of_float_decimal (7.65 /. 100.))) ;;
let r3 = Bignum.(r1 + r2) ;;

let my_to_string v =
  Bignum.(v |> round_decimal ~dir:`Nearest ~digits:2
            |> to_string_hum ~decimals:2) ;;

let () =
  Printf.printf "before tax: %s\n" (my_to_string r1);
  Printf.printf "tax:        %s\n" (my_to_string r2);
  Printf.printf "total:      %s\n" (my_to_string r3);
;;


use Math::Decimal qw(dec_canonise dec_add dec_mul dec_rndiv_and_rem);

@check = (
    [<Hamburger 5.50 4000000000000000>],
    [<Milkshake 2.86                2>]
);

my $fmt = "%-10s %8s %18s %22s\n";
printf $fmt, <Item Price Quantity Extension>;

my $subtotal = dec_canonise(0);
for $line (@check) {
    ($item,$price,$quant) = @$line;
    $dp = dec_canonise($price); $dq = dec_canonise($quant);
    my $extension = dec_mul($dp,$dq);
    $subtotal = dec_add($subtotal, $extension);
    printf $fmt, $item, $price, $quant, rnd($extension);
}

my $rate  = dec_canonise(0.0765);
my $tax   = dec_mul($subtotal,$rate);
my $total = dec_add($subtotal,$tax);

printf $fmt, '', '', '',          '-----------------';
printf $fmt, '', '', 'Subtotal ', rnd($subtotal);
printf $fmt, '', '', 'Tax ',      rnd($tax);
printf $fmt, '', '', 'Total ',    rnd($total);

sub rnd {
    ($q, $r) = dec_rndiv_and_rem("FLR", @_[0], 1);
    $q . substr((sprintf "%.2f", $r), 1, 3);
}


with javascript_semantics
requires("1.0.0") -- (mpfr_set_default_prec[ision] has been renamed)
include mpfr.e
mpfr_set_default_precision(-20) -- ensure accuracy to at least 20 d.p.

mpfr total_price = mpfr_init("4000000000000000"),
     tmp = mpfr_init("5.5"),
     tax = mpfr_init("0.0765"),
     total = mpfr_init()
mpfr_mul(total_price,total_price,tmp)
mpfr_set_str(tmp,"2.86")
mpfr_mul_si(tmp,tmp,2)
mpfr_add(total_price,total_price,tmp)
mpfr_mul(tax,total_price,tax)
mpfr_add(total,total_price,tax)
printf(1,"Total before tax:%21s\n",{mpfr_get_fixed(total_price,2)})
printf(1,"             Tax:%21s\n",{mpfr_get_fixed(tax,2)})
printf(1,"           Total:%21s\n",{mpfr_get_fixed(total,2)})


(scl 2)
(let
   (Before
      (+
         (* 4000000000000000 5.50)
         (* 2 2.86) )
      Tax (*/ Before 7.65 100.00)
      Total (+ Before Tax)
      Fmt (17 27) )
   (tab Fmt "Total before tax:" (format Before *Scl "." ","))
   (tab Fmt "Tax:" (format Tax *Scl "." ","))
   (tab Fmt "Total:" (format Total *Scl "." ",")) )


from decimal import Decimal as D
from collections import namedtuple

Item = namedtuple('Item', 'price, quant')

items = dict( hamburger=Item(D('5.50'), D('4000000000000000')),
              milkshake=Item(D('2.86'), D('2')) )
tax_rate = D('0.0765')

fmt = "%-10s %8s %18s %22s"
print(fmt % tuple('Item Price Quantity Extension'.upper().split()))

total_before_tax = 0
for item, (price, quant) in sorted(items.items()):
    ext = price * quant
    print(fmt % (item, price, quant, ext))
    total_before_tax += ext
print(fmt % ('', '', '', '--------------------'))
print(fmt % ('', '', 'subtotal', total_before_tax))

tax = (tax_rate * total_before_tax).quantize(D('0.00'))
print(fmt % ('', '', 'Tax', tax))

total = total_before_tax + tax
print(fmt % ('', '', '', '--------------------'))
print(fmt % ('', '', 'Total', total))


#lang racket
(define (cents-* x y)
  (/ (round (* 100 x y)) 100))

(struct item (name count price))

(define (string-pad-right len . strs)
  (define all (apply string-append strs))
  (string-append  all (make-string (- len (string-length all)) #\space)))

(define (string-pad-left len . strs)
  (define all (apply string-append strs))
  (string-append  (make-string (- len (string-length all)) #\space) all))

(define (show-formated name count price total)
  (printf "~a ~a ~a -> ~a\n"
          (string-pad-right 10 name)
          (string-pad-left 18 count)
          (string-pad-left 8 price)
          (string-pad-left 23 total)
          ))

(define (show-item it)
  (show-formated (item-name it)
                 (~r (item-count it))
                 (string-append "$" (~r (item-price it) #:precision '(= 2)))
                 (string-append "$" (~r (cents-* (item-count it) (item-price it)) #:precision '(= 2)))
          ))

(define (show-total all tax-rate)
  (define net (for/sum ([it (in-list all)])
                       (cents-* (item-count it) (item-price it))))
  (define tax (cents-* net tax-rate))
  (show-formated "" "" "net" (string-append "$" (~r net #:precision '(= 2))))
  (show-formated "" "" "tax" (string-append "$" (~r tax #:precision '(= 2))))
  (show-formated "" "" "total" (string-append "$" (~r (+ net tax) #:precision '(= 2))))
  )

(define hamburger (item "hamburger" 4000000000000000 #e5.50))
(define milkshake (item "milkshake" 2 #e2.86))
(define all (list hamburger milkshake))

(for-each show-item all)
(newline)
(show-total all (/ #e7.65 100))


my @check = q:to/END/.lines.map: { [.split(/\s+/)] };
    Hamburger   5.50    4000000000000000
    Milkshake   2.86    2
    END

my $tax-rate = 0.0765;

my $fmt = "%-10s %8s %18s %22s\n";

printf $fmt, <Item Price Quantity Extension>;

my $subtotal = [+] @check.map: -> [$item,$price,$quant] {
    my $extension = $price * $quant;
    printf $fmt, $item, $price, $quant, fix2($extension);
    $extension;
}

printf $fmt, '', '', '', '-----------------';
printf $fmt, '', '', 'Subtotal ', $subtotal;

my $tax = ($subtotal * $tax-rate).round(0.01);
printf $fmt, '', '', 'Tax ', $tax;

my $total = $subtotal + $tax;
printf $fmt, '', '', 'Total ', $total;

# make up for lack of a Rat fixed-point printf format
sub fix2($x) { ($x + 0.001).subst(/ <?after \.\d\d> .* $ /, '') }


/*REXX program shows a method of computing the total price and tax  for purchased items.*/
numeric digits 200                                        /*support for gihugic numbers.*/
taxRate= 7.65                                             /*number is:   nn   or   nn%  */
if right(taxRate, 1)\=='%'  then taxRate= taxRate / 100   /*handle plain tax rate number*/
taxRate= strip(taxRate, , '%')                            /*strip the  %   (if present).*/
item.  =;                          items= 0               /*zero out the register.      */
item.1 = '4000000000000000  $5.50  hamburger'             /*the  first  item purchased. */
item.2 = '               2  $2.86  milkshake'             /* "  second    "      "      */
say  center('quantity', 22)          center("item", 22)           center('price', 22)
hdr= center('',         27, "─")     center('',     20, "─")      center('',      27, "─")
say hdr;                             total= 0
         do j=1  while item.j\==''                        /*calculate the total and tax.*/
         parse var item.j   quantity price thing          /*ring up an item on register.*/
         items    = items + quantity                      /*tally the number of items.  */
         price    = translate(price, , '$')               /*maybe scrub out the $ symbol*/
         subtotal = quantity * price                      /*calculate the     sub-total.*/
         total    = total + subtotal                      /*    "      "  running total.*/
         say right(quantity, 27)     left(thing, 20)        show$(subtotal)
         end   /*j*/
say                                              /*display a blank line for separator.  */
say translate(hdr, '═', "─")                     /*display the separator part of the hdr*/
tax= format(total * taxRate, , 2)                /*round the total tax for all the items*/
say right(items  "(items)", 35)     right('total=', 12)            show$(total)
say right('tax at'  (taxRate * 100 / 1)"%=", 48)                   show$(tax)
say
say right('grand total=', 48)                                   show$(total+tax)
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
show$:  return right( '$'arg(1), 27)             /*right─justify and format a number.   */


# Project  : Currency

nhamburger  = "4000000000"
phamburger  = "5.50"
nmilkshakes = "2"
pmilkshakes = "2.86"
taxrate = "0.0765"
price = nhamburger * phamburger + nmilkshakes * pmilkshakes
tax = price * taxrate
see "total price before tax : " + price + nl
see "tax thereon @ 7.65 : " + tax + nl
see "total price after tax  : " + (price + tax) + nl


require 'bigdecimal/util'

before_tax = 4000000000000000 * 5.50.to_d + 2 * 2.86.to_d
tax        = (before_tax * 0.0765.to_d).round(2)
total      = before_tax + tax

puts "Before tax: $#{before_tax.to_s('F')}
Tax: $#{tax.to_s('F')}
Total: $#{total.to_s('F')}"


extern crate num_bigint; // 0.3.0
extern crate num_rational; // 0.3.0

use num_bigint::BigInt;
use num_rational::BigRational;

use std::ops::{Add, Mul};
use std::fmt;

fn main() {
    let hamburger = Currency::new(5.50);
    let milkshake = Currency::new(2.86);
    let pre_tax = hamburger * 4_000_000_000_000_000 + milkshake * 2;
    println!("Price before tax: {}", pre_tax);
    let tax = pre_tax.calculate_tax();
    println!("Tax: {}", tax);
    let post_tax = pre_tax + tax;
    println!("Price after tax: {}", post_tax);
}

#[derive(Debug)]
struct Currency {
    amount: BigRational,
}

impl Add for Currency {

    type Output = Self;

    fn add(self, other: Self) -> Self {
        Self {
            amount: self.amount + other.amount,
        }
    }
}

impl Mul<u64> for Currency {

    type Output = Self;

    fn mul(self, other: u64) -> Self {
        Self {
            amount: self.amount * BigInt::from(other),
        }
    }
}

impl fmt::Display for Currency {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let cents = (&self.amount * BigInt::from(100)).to_integer();
        write!(f, "${}.{}", &cents / 100, &cents % 100)
    }
}

impl Currency {

    fn new(num: f64) -> Self {
        Self {
            amount: BigRational::new(((num * 100.0) as i64).into(), 100.into())
        }
    }

    fn calculate_tax(&self) -> Self {
        let tax_val = BigRational::new(765.into(), 100.into());// 7,65 -> 0.0765 after the next line
        let amount = (&self.amount * tax_val).ceil() / BigInt::from(100);
        Self {
            amount
        }
    }
}


import java.text.NumberFormat
import java.util.Locale

object SizeMeUp extends App {

  val menu: Map[String, (String, Double)] = Map("burg" ->("Hamburger XL", 5.50), "milk" ->("Milkshake", 2.86))
  val order = List((4000000000000000L, "burg"), (2L, "milk"))

  Locale.setDefault(new Locale("ru", "RU"))

  val (currSymbol, tax) = (NumberFormat.getInstance().getCurrency.getSymbol, 0.0765)

  def placeOrder(order: List[(Long, String)]) = {
    val totals = for ((qty, article) <- order) yield {
      val (desc, itemPrize) = menu(article)
      val (items, post) = (qty, qty * BigDecimal(itemPrize))
      println(f"$qty%16d\t$desc%-16s\t$currSymbol%4s$itemPrize%6.2f\t$post%,25.2f")
      (items, post)
    }
    totals.foldLeft((0L, BigDecimal(0))) { (acc, n) => (acc._1 + n._1, acc._2 + n._2)}
  }

  val (items, beforeTax) = placeOrder(order)

  println(f"$items%16d\t${"ordered items"}%-16s${'\t' + "  Subtotal" + '\t'}$beforeTax%,25.2f")

  val taxation = beforeTax * tax
  println(f"${" " * 16 + '\t' + " " * 16 + '\t' + f"${tax * 100}%5.2f%% tax" + '\t'}$taxation%,25.2f")
  println(f"${" " * 16 + '\t' + " " * 16 + '\t' + "Amount due" + '\t'}${beforeTax + taxation}%,25.2f")
}


struct Item {
    name, price, quant
}

var check = %q{
    Hamburger   5.50    4000000000000000
    Milkshake   2.86    2
}.lines.grep(/\S/).map { Item(.words...) }

var tax_rate = 0.0765
var fmt = "%-10s %8s %18s %22s\n"

printf(fmt, %w(Item Price Quantity Extension)...)

var subtotal = check.map { |item|
    var extension = Num(item.price)*Num(item.quant)
    printf(fmt, item.name, item.price, item.quant, extension.round(-2))
    extension
}.sum(0)

printf(fmt, '', '', '', '-----------------')
printf(fmt, '', '', 'Subtotal ', subtotal)

var tax = (subtotal * tax_rate -> round(-2))
printf(fmt, '', '', 'Tax ', tax)

var total = subtotal+tax
printf(fmt, '', '', 'Total ', total)


check := #(
    " amount         name           price  "
    (4000000000000000 'hamburger'    5.50s2 )
    (2                'milkshakes'   2.86s2 )
).
tax := 7.65s2.
fmt := '%-10s %10P %22P %26P\n'.

totalSum := 0.
totalTax := 0.

Transcript clear.
Transcript printf:fmt withAll:#('Item' 'Price' 'Qty' 'Extension').
Transcript printCR:('-' ,* 72).

check do:[:entry|
    |amount name price itemTotal itemTax|

    amount := entry[1].
    name   := entry[2].
    price  := entry[3].
    itemTotal := (price*amount).
    itemTax   := ((price*amount)*tax/100) roundedToScale.

    totalSum := totalSum + itemTotal.
    totalTax := totalTax + itemTax.
    Transcript printf:fmt
               withAll:{name . price . amount . itemTotal}.
].
Transcript printCR:('-' ,* 72).
Transcript printf:fmt withAll:{'' . '' . 'Subtotal' . totalSum}.
Transcript printf:fmt withAll:{'' . '' . 'Tax' . totalTax}.
Transcript printf:fmt withAll:{'' . '' . 'Total' . (totalSum+totalTax)}.

Transcript cr; printCR:('Enjoy your Meal & Thank You for Dining at Milliways')


import Foundation

extension Decimal {
  func rounded(_ scale: Int, _ roundingMode: NSDecimalNumber.RoundingMode) -> Decimal {
    var result = Decimal()
    var localCopy = self
    NSDecimalRound(&result, &localCopy, scale, roundingMode)
    return result
  }
}

let costHamburgers = Decimal(4000000000000000) * Decimal(5.50)
let costMilkshakes = Decimal(2) * Decimal(2.86)
let totalBeforeTax = costMilkshakes + costHamburgers
let taxesToBeCollected = (Decimal(string: "0.0765")! * totalBeforeTax).rounded(2, .bankers)

print("Price before tax: $\(totalBeforeTax)")
print("Total tax to be collected: $\(taxesToBeCollected)")
print("Total with taxes: $\(totalBeforeTax + taxesToBeCollected)")


package require math::decimal
namespace import math::decimal::*

set hamburgerPrice [fromstr 5.50]
set milkshakePrice [fromstr 2.86]
set taxRate [/ [fromstr 7.65] [fromstr 100]]

set burgers 4000000000000000
set shakes 2
set net [+ [* [fromstr $burgers] $hamburgerPrice] [* [fromstr $shakes] $milkshakePrice]]
set tax [round_up [* $net $taxRate] 2]
set total [+ $net $tax]

puts "net=[tostr $net], tax=[tostr $tax], total=[tostr $total]"


Public Sub currency_task()
    '4000000000000000 hamburgers at $5.50 each
    Dim number_of_hamburgers As Variant
    number_of_hamburgers = CDec(4E+15)
    Dim price_of_hamburgers As Currency
    price_of_hamburgers = 5.5
    '2 milkshakes at $2.86 each, and
    Dim number_of_milkshakes As Integer
    number_of_milkshakes = 2
    Dim price_of_milkshakes As Currency
    price_of_milkshakes = 2.86
    'a tax rate of 7.65%.
    Dim tax_rate As Single
    tax_rate = 0.0765
    'the total price before tax
    Dim total_price_before_tax As Variant
    total_price_before_tax = number_of_hamburgers * price_of_hamburgers
    total_price_before_tax = total_price_before_tax + number_of_milkshakes * price_of_milkshakes
    Debug.Print "Total price before tax "; Format(total_price_before_tax, "Currency")
    'the tax
    Dim tax As Variant
    tax = total_price_before_tax * tax_rate
    Debug.Print "Tax "; Format(tax, "Currency")
    'the total with tax
    Debug.Print "Total with tax "; Format(total_price_before_tax + tax, "Currency")
End Sub


import "/big" for BigRat

var hamburgers     = BigRat.new("4000000000000000")
var milkshakes     = BigRat.two
var price1         = BigRat.fromFloat(5.5)
var price2         = BigRat.fromFloat(2.86)
var taxPc          = BigRat.fromFloat(0.0765)
var totalPc        = BigRat.fromFloat(1.0765)
var totalPreTax    = hamburgers*price1 + milkshakes*price2
var totalTax       = taxPc * totalPreTax
var totalAfterTax  = totalPreTax + totalTax
System.print("Total price before tax : %((totalPreTax).toDecimal(2))")
System.print("Tax                    :  %((totalTax).toDecimal(2))")
System.print("Total price after tax  : %((totalAfterTax).toDecimal(2))")


var priceList=Dictionary("hamburger",550, "milkshake",286);
var taxRate=765;  // percent*M
const M=0d10_000;

fcn toBucks(n){ "$%,d.%02d".fmt(n.divr(100).xplode()) }
fcn taxIt(n)  { d,c:=n.divr(M).apply('*(taxRate)); d + (c+5000)/M; }
fcn calcTab(items){ // (hamburger,15), (milkshake,100) ...
   items=vm.arglist;
   fmt:="%-10s %8s %18s %26s";
   fmt.fmt("Item Price Quantity Extension".split().xplode()).println();

   totalBeforeTax:=0;
   foreach item,n in (items.sort(fcn(a,b){ a[0]<b[0] })){
      price:=priceList[item]; t:=price*n;
      fmt.fmt(item,toBucks(price),n,toBucks(t)).println();
      totalBeforeTax+=t;
   }
   fmt.fmt("","","","--------------------").println();
   fmt.fmt("","","subtotal",toBucks(totalBeforeTax)).println();

   tax:=taxIt(totalBeforeTax);
   fmt.fmt("","","Tax",toBucks(tax)).println();

   fmt.fmt("","","","--------------------").println();
   fmt.fmt("","","Total",toBucks(totalBeforeTax + tax)).println();
}


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’))


*        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


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


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;


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


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.


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


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"]
]


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])
}


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")
$)


#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;
}


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");
            }
        }
    }
}


#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;
}


Class Utils.Check [ Abstract ]
{

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

}


(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"))))


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


(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))))


BEGIN
    # find some cuban primes (using the definition: a prime p is a cuban prime if   #
    #                                                   p = n^3 - ( n - 1 )^3       #
    #                                                   for some n > 0)             #

    # returns a string representation of n with commas                              #
    PROC commatise = ( LONG INT n )STRING:
         BEGIN
            STRING result      := "";
            STRING unformatted  = whole( n, 0 );
            INT    ch count    := 0;
            FOR c FROM UPB unformatted BY -1 TO LWB unformatted DO
                IF   ch count <= 2 THEN ch count +:= 1
                ELSE                    ch count  := 1; "," +=: result
                FI;
                unformatted[ c ] +=: result
            OD;
            result
         END # commatise # ;

    # sieve the primes                                                              #
    INT sieve max = 2 000 000;
    [ sieve max ]BOOL sieve; FOR i TO UPB sieve DO sieve[ i ] := TRUE OD;
    sieve[ 1 ] := FALSE;
    FOR s FROM 2 TO ENTIER sqrt( sieve max ) DO
        IF sieve[ s ] THEN
            FOR p FROM s * s BY s TO sieve max DO sieve[ p ] := FALSE OD
        FI
    OD;
    # count the primes, we can ignore 2, as we know it isn't a cuban prime          #
    sieve[ 2 ] := FALSE;
    INT prime count := 0;
    FOR s TO UPB sieve DO IF sieve[ s ] THEN prime count +:= 1 FI OD;
    # construct a list of the primes                                                #
    [ 1 : prime count ]INT primes;
    INT prime pos := LWB primes;
    FOR s FROM LWB sieve TO UPB sieve DO
        IF sieve[ s ] THEN primes[ prime pos ] := s; prime pos +:= 1 FI
    OD;

    # find the cuban primes                                                         #
    INT       cuban count   := 0;
    LONG INT  final cuban   := 0;
    INT       max cuban      = 100 000; # mximum number of cubans to find           #
    INT       print limit    =     200; # show all cubans up to this one            #
    print( ( "First ", commatise( print limit ), " cuban primes: ", newline ) );
    LONG INT prev cube      := 1;
    FOR n FROM 2 WHILE
        LONG INT this cube   = ( LENG n * n ) * n;
        LONG INT p           = this cube - prev cube;
        prev cube           := this cube;
        IF ODD p THEN
            # 2 is not a cuban prime so we only test odd numbers                    #
            BOOL is prime   := TRUE;
            INT max factor   = SHORTEN ENTIER long sqrt( p );
            FOR f FROM LWB primes WHILE is prime AND primes[ f ] <= max factor DO
                is prime    := p MOD primes[ f ] /= 0
            OD;
            IF is prime THEN
                # have a cuban prime                                                #
                cuban count +:= 1;
                IF cuban count <= print limit THEN
                    # must show this cuban                                          #
                    STRING p formatted = commatise( p );
                    print( ( "          "[ UPB p formatted : ], p formatted ) );
                    IF cuban count MOD 10 = 0 THEN print( ( newline ) ) FI
                FI;
                final cuban := p
            FI
        FI;
        cuban count < max cuban
    DO SKIP OD;
    IF cuban count MOD 10 /= 0 THEN print( ( newline ) ) FI;
    print( ( "The ", commatise( max cuban ), " cuban prime is: ", commatise( final cuban ), newline ) )
END


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`


( ( cubanprimes
  =
    .   !arg:(?N.?bigN)
      & :?cubans
      & (0.1.1):(?cube100k.?cube1.?count)
      & 0:?i
      &   whl
        ' ( 1+!i:?i
          & !i+1:?j
          & !j^3:?cube2
          & !cube2+-1*!cube1:?diff
          & ( !diff^1/2:~(!diff^?)
            |   (   !count:~>!N
                  & !diff !cubans:?cubans
                |
                )
              & ( !count:<!bigN
                | !diff:?cube100k&~
                )
              & 1+!count:?count
            )
          & !cube2:?cube1
          )
      & ( columnwidth
        =   cols
          .   !arg:(%@:@(?:? [?cols)) ?
            & div$(-1+!cols.3)*4+1
        )
      & columnwidth$!cubans:?colwidth
      & \n:?table
      & 0:?col
      & ( format
        =   n col cif R
          .   !arg:(?n.?col)
            & -1:?cif
            &     vap
                $ ( (
                    =
                      .   (   mod$(1+!cif:?cif.3):0
                            & -2+!col:?col
                            & ","
                          | -1+!col:?col&
                          )
                          !arg
                    )
                  . rev$!n
                  )
              : "," ?R
            & rev$(str$!R):?R
            &   whl
              ' ( !col+-1:?col:>-2
                & " " !R:?R
                )
            & str$!R
        )
      &   whl
        ' ( !cubans:%?cuban ?cubans
          & mod$(1+!col:?col.10):?col
          &     (!col:0&\n|" ")
                format$(!cuban.!colwidth)
                !table
            : ?table
          )
      & out$(str$("The first " !N " cuban primes are: " !table))
      &   out
        $ ( str
          $ ( "The 100,000th cuban prime is "
              format$(!cube100k.columnwidth$!cube100k)
            )
          )
  )
& cubanprimes$(200.100000)
)


#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

typedef long long llong_t;
struct PrimeArray {
    llong_t *ptr;
    size_t size;
    size_t capacity;
};

struct PrimeArray allocate() {
    struct PrimeArray primes;

    primes.size = 0;
    primes.capacity = 10;
    primes.ptr = malloc(primes.capacity * sizeof(llong_t));

    return primes;
}

void deallocate(struct PrimeArray *primes) {
    free(primes->ptr);
    primes->ptr = NULL;
}

void push_back(struct PrimeArray *primes, llong_t p) {
    if (primes->size >= primes->capacity) {
        size_t new_capacity = (3 * primes->capacity) / 2 + 1;
        llong_t *temp = realloc(primes->ptr, new_capacity * sizeof(llong_t));
        if (NULL == temp) {
            fprintf(stderr, "Failed to reallocate the prime array.");
            exit(1);
        } else {
            primes->ptr = temp;
            primes->capacity = new_capacity;
        }
    }

    primes->ptr[primes->size++] = p;
}

int main() {
    const int cutOff = 200, bigUn = 100000, chunks = 50, little = bigUn / chunks;
    struct PrimeArray primes = allocate();
    int c = 0;
    bool showEach = true;
    llong_t u = 0, v = 1, i;

    push_back(&primes, 3);
    push_back(&primes, 5);

    printf("The first %d cuban primes:\n", cutOff);
    for (i = 1; i < LLONG_MAX; ++i) {
        bool found = false;
        llong_t mx = ceil(sqrt(v += (u += 6)));
        llong_t j;

        for (j = 0; j < primes.size; ++j) {
            if (primes.ptr[j] > mx) {
                break;
            }
            if (v % primes.ptr[j] == 0) {
                found = true;
                break;
            }
        }
        if (!found) {
            c += 1;
            if (showEach) {
                llong_t z;
                for (z = primes.ptr[primes.size - 1] + 2; z <= v - 2; z += 2) {
                    bool fnd = false;

                    for (j = 0; j < primes.size; ++j) {
                        if (primes.ptr[j] > mx) {
                            break;
                        }
                        if (z % primes.ptr[j] == 0) {
                            fnd = true;
                            break;
                        }
                    }
                    if (!fnd) {
                        push_back(&primes, z);
                    }
                }
                push_back(&primes, v);
                printf("%11lld", v);
                if (c % 10 == 0) {
                    printf("\n");
                }
                if (c == cutOff) {
                    showEach = false;
                    printf("\nProgress to the %dth cuban prime: ", bigUn);
                }
            }
            if (c % little == 0) {
                printf(".");
                if (c == bigUn) {
                    break;
                }
            }
        }
    }
    printf("\nThe %dth cuban prime is %lld\n", c, v);

    deallocate(&primes);
    return 0;
}


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


using System;
using System.Collections.Generic;
using System.Linq;

static class Program
{
    static List<long> primes = new List<long>() { 3, 5 };

     static void Main(string[] args)
    {
        const int cutOff = 200;
        const int bigUn = 100000;
        const int chunks = 50;
        const int little = bigUn / chunks;
        const string tn = " cuban prime";
        Console.WriteLine("The first {0:n0}{1}s:", cutOff, tn);
        int c = 0;
        bool showEach = true;
        long u = 0, v = 1;
        DateTime st = DateTime.Now;
        for (long i = 1; i <= long.MaxValue; i++)
        {
            bool found = false;
            int mx = System.Convert.ToInt32(Math.Ceiling(Math.Sqrt(v += (u += 6))));
            foreach (long item in primes)
            {
                if (item > mx) break;
                if (v % item == 0) { found = true; break; }
            }
            if (!found)
            {
                c += 1; if (showEach)
                {
                    for (var z = primes.Last() + 2; z <= v - 2; z += 2)
                    {
                        bool fnd = false;
                        foreach (long item in primes)
                        {
                            if (item > mx) break;
                            if (z % item == 0) { fnd = true; break; }
                        }
                        if (!fnd) primes.Add(z);
                    }
                    primes.Add(v); Console.Write("{0,11:n0}", v);
                    if (c % 10 == 0) Console.WriteLine();
                    if (c == cutOff)
                    {
                        showEach = false;
                        Console.Write("\nProgress to the {0:n0}th{1}: ", bigUn, tn);
                    }
                }
                if (c % little == 0) { Console.Write("."); if (c == bigUn) break; }
            }
        }
        Console.WriteLine("\nThe {1:n0}th{2} is {0,17:n0}", v, c, tn);
        Console.WriteLine("Computation time was {0} seconds", (DateTime.Now - st).TotalSeconds);
        if (System.Diagnostics.Debugger.IsAttached) Console.ReadKey();
    }
}


      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


' 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


#include <iostream>
#include <vector>
#include <chrono>
#include <climits>
#include <cmath>

using namespace std;

vector <long long> primes{ 3, 5 };

int main()
{
	cout.imbue(locale(""));
	const int cutOff = 200, bigUn = 100000,
	          chunks = 50, little = bigUn / chunks;
    const char tn[] = " cuban prime";
	cout << "The first " << cutOff << tn << "s:" << endl;
	int c = 0;
	bool showEach = true;
	long long u = 0, v = 1;
	auto st = chrono::system_clock::now();

	for (long long i = 1; i <= LLONG_MAX; i++)
	{
		bool found = false;
		long long mx = (long long)(ceil(sqrt(v += (u += 6))));
		for (long long item : primes)
		{
			if (item > mx) break;
			if (v % item == 0) { found = true; break; }
		}
		if (!found)
		{
			c += 1; if (showEach)
			{
				for (long long z = primes.back() + 2; z <= v - 2; z += 2)
				{
					bool fnd = false;
					for (long long item : primes)
					{
						if (item > mx) break;
						if (z % item == 0) { fnd = true; break; }
					}
					if (!fnd) primes.push_back(z);
				}
				primes.push_back(v); cout.width(11); cout << v;
				if (c % 10 == 0) cout << endl;
				if (c == cutOff)
				{
					showEach = false;
					cout << "\nProgress to the " << bigUn << "th" << tn << ": ";
				}
			}
			if (c % little == 0) { cout << "."; if (c == bigUn) break; }
		}
	}
	cout << "\nThe " << c << "th" << tn << " is " << v;
	chrono::duration<double> elapsed_seconds = chrono::system_clock::now() - st;
	cout << "\nComputation time was " << elapsed_seconds.count() << " seconds" << endl;
	return 0;
}


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)
    }
}


;;; Show the first 200 and the 100,000th cuban prime.
;;; Cuban primes are the difference of 2 consecutive cubes.

(defun primep (n)
  (cond ((< n 4) t)
        ((evenp n) nil)
        ((zerop (mod n 3)) nil)
        (t (loop for i from 5 upto (isqrt n) by 6
              when (or
                     (zerop (mod n i))
                     (zerop (mod n (+ i 2))))
                return nil
              finally (return t)))))

(defun cube (n) (* n n n))

(defun cuban (n)
  (loop for i from 1
        for j from 2
        for cube-diff = (- (cube j) (cube i))
          when (primep cube-diff)
            collect cube-diff into cuban-primes
            and count i into counter
          when (= counter n)
            return cuban-primes))

(format t "~a~%" "1st to 200th cuban prime numbers:")
(format t
    "~{~<~%~,120:;~10:d ~>~}~%"
    (cuban 200))

(format t "~%100,000th cuban prime number = ~:d"
    (car (last (cuban 100000))))

(princ #\newline)


import std.math;
import std.stdio;

void main() {
    long[] primes = [3, 5];

    immutable cutOff = 200;
    immutable bigUn = 100_000;
    immutable chunks = 50;
    immutable little = bigUn / chunks;
    immutable tn = " cuban prime";
    writefln("The first %s%ss:", cutOff, tn);
    int c;
    bool showEach = true;
    long u;
    long v = 1;
    for (long i = 1; i > 0; ++i) {
        bool found;
        u += 6;
        v += u;
        int mx = cast(int)ceil(sqrt(cast(real)v));
        foreach (item; primes) {
            if (item > mx) break;
            if (v % item == 0) {
                found = true;
                break;
            }
        }
        if (!found) {
            c++;
            if (showEach) {
                for (auto z = primes[$-1] + 2; z <= v - 2; z += 2) {
                    bool fnd;
                    foreach (item; primes) {
                        if (item > mx) break;
                        if (z % item == 0) {
                            fnd = true;
                            break;
                        }
                    }
                    if (!fnd) {
                        primes ~= z;
                    }
                }
                primes ~= v;
                writef("%11d", v);
                if (c % 10 == 0) writeln;
                if (c == cutOff) {
                    showEach = false;
                    writef("\nProgress to the %sth%s: ", bigUn, tn);
                }
            }
            if (c % little == 0) {
                write('.');
                if (c == bigUn) {
                    break;
                }
            }
        }
    }
    writefln("\nThe %sth%s is %17s", c, tn, v);
}


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")
        }
    }
}


// Generate cuban primes. Nigel Galloway: June 9th., 2019
let cubans=Seq.unfold(fun n->Some(n*n*n,n+1L)) 1L|>Seq.pairwise|>Seq.map(fun(n,g)->g-n)|>Seq.filter(isPrime64)
let cL=let g=System.Globalization.CultureInfo("en-GB") in (fun (n:int64)->n.ToString("N0",g))


USING: formatting grouping io kernel lists lists.lazy math
math.primes sequences tools.memory.private ;
IN: rosetta-code.cuban-primes

: cuban-primes ( n -- seq )
    1 lfrom [ [ 3 * ] [ 1 + * ] bi 1 + ] <lazy-map>
    [ prime? ] <lazy-filter> ltake list>array ;

200 cuban-primes 10 <groups>
[ [ commas ] map [ "%10s" printf ] each nl ] each nl

1e5 cuban-primes last commas "100,000th cuban prime is: %s\n"
printf


#include <algorithm>
#include <iostream>
#include <initializer_list>
#include <map>
#include <vector>

const int MAX_ALL_FACTORS = 100000;
const int algorithm = 2;
int divisions = 0;

//Note: Cyclotomic Polynomials have small coefficients.  Not appropriate for general polynomial usage.
class Term {
private:
    long m_coefficient;
    long m_exponent;

public:
    Term(long c, long e) : m_coefficient(c), m_exponent(e) {
        // empty
    }

    Term(const Term &t) : m_coefficient(t.m_coefficient), m_exponent(t.m_exponent) {
        // empty
    }

    long coefficient() const {
        return m_coefficient;
    }

    long degree() const {
        return m_exponent;
    }

    Term operator -() const {
        return { -m_coefficient, m_exponent };
    }

    Term operator *(const Term &rhs) const {
        return { m_coefficient * rhs.m_coefficient, m_exponent + rhs.m_exponent };
    }

    Term operator +(const Term &rhs) const {
        if (m_exponent != rhs.m_exponent) {
            throw std::runtime_error("Exponents not equal");
        }
        return { m_coefficient + rhs.m_coefficient, m_exponent };
    }

    friend std::ostream &operator<<(std::ostream &, const Term &);
};

std::ostream &operator<<(std::ostream &os, const Term &t) {
    if (t.m_coefficient == 0) {
        return os << '0';
    }
    if (t.m_exponent == 0) {
        return os << t.m_coefficient;
    }
    if (t.m_coefficient == 1) {
        if (t.m_exponent == 1) {
            return os << 'x';
        }
        return os << "x^" << t.m_exponent;
    }
    if (t.m_coefficient == -1) {
        if (t.m_exponent == 1) {
            return os << "-x";
        }
        return os << "-x^" << t.m_exponent;
    }
    if (t.m_exponent == 1) {
        return os << t.m_coefficient << 'x';
    }
    return os << t.m_coefficient << "x^" << t.m_exponent;
}

class Polynomial {
public:
    std::vector<Term> polynomialTerms;

    Polynomial() {
        polynomialTerms.push_back({ 0, 0 });
    }

    Polynomial(std::initializer_list<int> values) {
        if (values.size() % 2 != 0) {
            throw std::runtime_error("Length must be even.");
        }

        bool ready = false;
        long t;
        for (auto v : values) {
            if (ready) {
                polynomialTerms.push_back({ t, v });
            } else {
                t = v;
            }
            ready = !ready;
        }
        std::sort(
            polynomialTerms.begin(), polynomialTerms.end(),
            [](const Term &t, const Term &u) {
                return u.degree() < t.degree();
            }
        );
    }

    Polynomial(const std::vector<Term> &termList) {
        if (termList.size() == 0) {
            polynomialTerms.push_back({ 0, 0 });
        } else {
            for (auto t : termList) {
                if (t.coefficient() != 0) {
                    polynomialTerms.push_back(t);
                }
            }
            if (polynomialTerms.size() == 0) {
                polynomialTerms.push_back({ 0, 0 });
            }
            std::sort(
                polynomialTerms.begin(), polynomialTerms.end(),
                [](const Term &t, const Term &u) {
                    return u.degree() < t.degree();
                }
            );
        }
    }

    Polynomial(const Polynomial &p) : Polynomial(p.polynomialTerms) {
        // empty
    }

    long leadingCoefficient() const {
        return polynomialTerms[0].coefficient();
    }

    long degree() const {
        return polynomialTerms[0].degree();
    }

    bool hasCoefficientAbs(int coeff) {
        for (auto term : polynomialTerms) {
            if (abs(term.coefficient()) == coeff) {
                return true;
            }
        }
        return false;
    }

    Polynomial operator+(const Term &term) const {
        std::vector<Term> termList;
        bool added = false;
        for (size_t index = 0; index < polynomialTerms.size(); index++) {
            auto currentTerm = polynomialTerms[index];
            if (currentTerm.degree() == term.degree()) {
                added = true;
                if (currentTerm.coefficient() + term.coefficient() != 0) {
                    termList.push_back(currentTerm + term);
                }
            } else {
                termList.push_back(currentTerm);
            }
        }
        if (!added) {
            termList.push_back(term);
        }
        return Polynomial(termList);
    }

    Polynomial operator*(const Term &term) const {
        std::vector<Term> termList;
        for (size_t index = 0; index < polynomialTerms.size(); index++) {
            auto currentTerm = polynomialTerms[index];
            termList.push_back(currentTerm * term);
        }
        return Polynomial(termList);
    }

    Polynomial operator+(const Polynomial &p) const {
        std::vector<Term> termList;
        int thisCount = polynomialTerms.size();
        int polyCount = p.polynomialTerms.size();
        while (thisCount > 0 || polyCount > 0) {
            if (thisCount == 0) {
                auto polyTerm = p.polynomialTerms[polyCount - 1];
                termList.push_back(polyTerm);
                polyCount--;
            } else if (polyCount == 0) {
                auto thisTerm = polynomialTerms[thisCount - 1];
                termList.push_back(thisTerm);
                thisCount--;
            } else {
                auto polyTerm = p.polynomialTerms[polyCount - 1];
                auto thisTerm = polynomialTerms[thisCount - 1];
                if (thisTerm.degree() == polyTerm.degree()) {
                    auto t = thisTerm + polyTerm;
                    if (t.coefficient() != 0) {
                        termList.push_back(t);
                    }
                    thisCount--;
                    polyCount--;
                } else if (thisTerm.degree() < polyTerm.degree()) {
                    termList.push_back(thisTerm);
                    thisCount--;
                } else {
                    termList.push_back(polyTerm);
                    polyCount--;
                }
            }
        }
        return Polynomial(termList);
    }

    Polynomial operator/(const Polynomial &v) {
        divisions++;

        Polynomial q;
        Polynomial r(*this);
        long lcv = v.leadingCoefficient();
        long dv = v.degree();
        while (r.degree() >= v.degree()) {
            long lcr = r.leadingCoefficient();
            long s = lcr / lcv;
            Term term(s, r.degree() - dv);
            q = q + term;
            r = r + v * -term;
        }

        return q;
    }

    friend std::ostream &operator<<(std::ostream &, const Polynomial &);
};

std::ostream &operator<<(std::ostream &os, const Polynomial &p) {
    auto it = p.polynomialTerms.cbegin();
    auto end = p.polynomialTerms.cend();
    if (it != end) {
        os << *it;
        it = std::next(it);
    }
    while (it != end) {
        if (it->coefficient() > 0) {
            os << " + " << *it;
        } else {
            os << " - " << -*it;
        }
        it = std::next(it);
    }
    return os;
}

std::vector<int> getDivisors(int number) {
    std::vector<int> divisiors;
    long root = (long)sqrt(number);
    for (int i = 1; i <= root; i++) {
        if (number % i == 0) {
            divisiors.push_back(i);
            int div = number / i;
            if (div != i && div != number) {
                divisiors.push_back(div);
            }
        }
    }
    return divisiors;
}

std::map<int, std::map<int, int>> allFactors;

std::map<int, int> getFactors(int number) {
    if (allFactors.find(number) != allFactors.end()) {
        return allFactors[number];
    }

    std::map<int, int> factors;
    if (number % 2 == 0) {
        auto factorsDivTwo = getFactors(number / 2);
        factors.insert(factorsDivTwo.begin(), factorsDivTwo.end());
        if (factors.find(2) != factors.end()) {
            factors[2]++;
        } else {
            factors.insert(std::make_pair(2, 1));
        }
        if (number < MAX_ALL_FACTORS) {
            allFactors.insert(std::make_pair(number, factors));
        }
        return factors;
    }
    long root = (long)sqrt(number);
    long i = 3;
    while (i <= root) {
        if (number % i == 0) {
            auto factorsDivI = getFactors(number / i);
            factors.insert(factorsDivI.begin(), factorsDivI.end());
            if (factors.find(i) != factors.end()) {
                factors[i]++;
            } else {
                factors.insert(std::make_pair(i, 1));
            }
            if (number < MAX_ALL_FACTORS) {
                allFactors.insert(std::make_pair(number, factors));
            }
            return factors;
        }
        i += 2;
    }
    factors.insert(std::make_pair(number, 1));
    if (number < MAX_ALL_FACTORS) {
        allFactors.insert(std::make_pair(number, factors));
    }
    return factors;
}

std::map<int, Polynomial> COMPUTED;
Polynomial cyclotomicPolynomial(int n) {
    if (COMPUTED.find(n) != COMPUTED.end()) {
        return COMPUTED[n];
    }

    if (n == 1) {
        // Polynomial: x - 1
        Polynomial p({ 1, 1, -1, 0 });
        COMPUTED.insert(std::make_pair(1, p));
        return p;
    }

    auto factors = getFactors(n);
    if (factors.find(n) != factors.end()) {
        // n prime
        std::vector<Term> termList;
        for (int index = 0; index < n; index++) {
            termList.push_back({ 1, index });
        }

        Polynomial cyclo(termList);
        COMPUTED.insert(std::make_pair(n, cyclo));
        return cyclo;
    } else if (factors.size() == 2 && factors.find(2) != factors.end() && factors[2] == 1 && factors.find(n / 2) != factors.end() && factors[n / 2] == 1) {
        // n = 2p
        int prime = n / 2;
        std::vector<Term> termList;
        int coeff = -1;

        for (int index = 0; index < prime; index++) {
            coeff *= -1;
            termList.push_back({ coeff, index });
        }

        Polynomial cyclo(termList);
        COMPUTED.insert(std::make_pair(n, cyclo));
        return cyclo;
    } else if (factors.size() == 1 && factors.find(2) != factors.end()) {
        // n = 2^h
        int h = factors[2];
        std::vector<Term> termList;
        termList.push_back({ 1, (int)pow(2, h - 1) });
        termList.push_back({ 1, 0 });

        Polynomial cyclo(termList);
        COMPUTED.insert(std::make_pair(n, cyclo));
        return cyclo;
    } else if (factors.size() == 1 && factors.find(n) != factors.end()) {
        // n = p^k
        int p = 0;
        int k = 0;
        for (auto iter = factors.begin(); iter != factors.end(); ++iter) {
            p = iter->first;
            k = iter->second;
        }
        std::vector<Term> termList;
        for (int index = 0; index < p; index++) {
            termList.push_back({ 1, index * (int)pow(p, k - 1) });
        }

        Polynomial cyclo(termList);
        COMPUTED.insert(std::make_pair(n, cyclo));
        return cyclo;
    } else if (factors.size() == 2 && factors.find(2) != factors.end()) {
        // n = 2^h * p^k
        int p = 0;
        for (auto iter = factors.begin(); iter != factors.end(); ++iter) {
            if (iter->first != 2) {
                p = iter->first;
            }
        }

        std::vector<Term> termList;
        int coeff = -1;
        int twoExp = (int)pow(2, factors[2] - 1);
        int k = factors[p];
        for (int index = 0; index < p; index++) {
            coeff *= -1;
            termList.push_back({ coeff, index * twoExp * (int)pow(p, k - 1) });
        }

        Polynomial cyclo(termList);
        COMPUTED.insert(std::make_pair(n, cyclo));
        return cyclo;
    } else if (factors.find(2) != factors.end() && ((n / 2) % 2 == 1) && (n / 2) > 1) {
        //  CP(2m)[x] = CP(-m)[x], n odd integer > 1
        auto cycloDiv2 = cyclotomicPolynomial(n / 2);
        std::vector<Term> termList;
        for (auto term : cycloDiv2.polynomialTerms) {
            if (term.degree() % 2 == 0) {
                termList.push_back(term);
            } else {
                termList.push_back(-term);
            }
        }

        Polynomial cyclo(termList);
        COMPUTED.insert(std::make_pair(n, cyclo));
        return cyclo;
    }

    // General Case

    if (algorithm == 0) {
        // slow - uses basic definition
        auto divisors = getDivisors(n);
        // Polynomial: (x^n - 1)
        Polynomial cyclo({ 1, n, -1, 0 });
        for (auto i : divisors) {
            auto p = cyclotomicPolynomial(i);
            cyclo = cyclo / p;
        }

        COMPUTED.insert(std::make_pair(n, cyclo));
        return cyclo;
    } else if (algorithm == 1) {
        //  Faster.  Remove Max divisor (and all divisors of max divisor) - only one divide for all divisors of Max Divisor
        auto divisors = getDivisors(n);
        int maxDivisor = INT_MIN;
        for (auto div : divisors) {
            maxDivisor = std::max(maxDivisor, div);
        }
        std::vector<int> divisorExceptMax;
        for (auto div : divisors) {
            if (maxDivisor % div != 0) {
                divisorExceptMax.push_back(div);
            }
        }

        //  Polynomial:  ( x^n - 1 ) / ( x^m - 1 ), where m is the max divisor
        auto cyclo = Polynomial({ 1, n, -1, 0 }) / Polynomial({ 1, maxDivisor, -1, 0 });
        for (int i : divisorExceptMax) {
            auto p = cyclotomicPolynomial(i);
            cyclo = cyclo / p;
        }

        COMPUTED.insert(std::make_pair(n, cyclo));
        return cyclo;
    } else if (algorithm == 2) {
        //  Fastest
        //  Let p ; q be primes such that p does not divide n, and q q divides n.
        //  Then CP(np)[x] = CP(n)[x^p] / CP(n)[x]
        int m = 1;
        auto cyclo = cyclotomicPolynomial(m);
        std::vector<int> primes;
        for (auto iter = factors.begin(); iter != factors.end(); ++iter) {
            primes.push_back(iter->first);
        }
        std::sort(primes.begin(), primes.end());
        for (auto prime : primes) {
            //  CP(m)[x]
            auto cycloM = cyclo;
            //  Compute CP(m)[x^p].
            std::vector<Term> termList;
            for (auto t : cycloM.polynomialTerms) {
                termList.push_back({ t.coefficient(), t.degree() * prime });
            }
            cyclo = Polynomial(termList) / cycloM;
            m = m * prime;
        }
        //  Now, m is the largest square free divisor of n
        int s = n / m;
        //  Compute CP(n)[x] = CP(m)[x^s]
        std::vector<Term> termList;
        for (auto t : cyclo.polynomialTerms) {
            termList.push_back({ t.coefficient(), t.degree() * s });
        }

        cyclo = Polynomial(termList);
        COMPUTED.insert(std::make_pair(n, cyclo));
        return cyclo;
    } else {
        throw std::runtime_error("Invalid algorithm");
    }
}

int main() {
    // initialization
    std::map<int, int> factors;
    factors.insert(std::make_pair(2, 1));
    allFactors.insert(std::make_pair(2, factors));

    // rest of main
    std::cout << "Task 1:  cyclotomic polynomials for n <= 30:\n";
    for (int i = 1; i <= 30; i++) {
        auto p = cyclotomicPolynomial(i);
        std::cout << "CP[" << i << "] = " << p << '\n';
    }

    std::cout << "Task 2:  Smallest cyclotomic polynomial with n or -n as a coefficient:\n";
    int n = 0;
    for (int i = 1; i <= 10; i++) {
        while (true) {
            n++;
            auto cyclo = cyclotomicPolynomial(n);
            if (cyclo.hasCoefficientAbs(i)) {
                std::cout << "CP[" << n << "] has coefficient with magnitude = " << i << '\n';
                n--;
                break;
            }
        }
    }

    return 0;
}


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)


include ./miller-rabin.fs

\ commatized print
\
: d.,r ( d n -- ) \ write double precision int, commatized.
    >r tuck dabs
    <# begin  2dup 1.000 d>  while  # # # [char] , hold  repeat #s rot sign #>
    r> over - spaces type ;

: .,r  ( n1 n2 -- ) \ write integer commatized.
    >r s>d r> d.,r ;

\ generate and print cuban primes
\
: sq  s" dup *" evaluate ; immediate
: next-cuban ( n -- n' p )
    begin
        1+ dup sq 3 * 1+ dup 3 and 0=  \ first check == 0 (mod 4)
        if 2 rshift dup prime?
            if exit
            else drop
            then
        else drop
        then
    again ;

: task1
    1
    20 0 do
        cr 10 0 do
            next-cuban 12 .,r
        loop
    loop drop ;

: task2
    cr ." The 100,000th cuban prime is "
    1  99999 0 do next-cuban drop loop next-cuban 0 .,r drop ;

task1 cr
task2 cr
bye


function isprime( n as ulongint ) as boolean
    if n mod 2 = 0 then return false
    for i as uinteger = 3 to int(sqr(n))+1 step 2
        if n mod i = 0 then return false
    next i
    return true
end function

function diff_cubes( n as uinteger ) as ulongint
    return 3*n*(n+1) + 1
end function

function padto( n as uinteger, s as integer ) as string
    dim as string outstr=""
    dim as integer k = len(str(n))
    for i as integer = 1 to s-k
        outstr = " " + outstr
    next i
    return outstr + str(n)
end function

dim as integer nc = 0, i = 1, di
while nc < 100000
    di = diff_cubes(i)
    if isprime(di) then
        nc += 1
        if nc <= 200 then
            print padto(di,8);" ";
            if nc mod 10 = 0 then print
        end if
        if nc = 100000 then
            print : print : print di
            exit while
        end if
    end if
    i += 1
wend


package main

import (
    "fmt"
    "math/big"
)

func commatize(n uint64) string {
    s := fmt.Sprintf("%d", n)
    le := len(s)
    for i := le - 3; i >= 1; i -= 3 {
        s = s[0:i] + "," + s[i:]
    }
    return s
}

func main() {
    var z big.Int
    var cube1, cube2, cube100k, diff uint64
    cubans := make([]string, 200)
    cube1 = 1
    count := 0
    for i := 1; ; i++ {
        j := i + 1
        cube2 = uint64(j * j * j)
        diff = cube2 - cube1
        z.SetUint64(diff)
        if z.ProbablyPrime(0) { // 100% accurate for z < 2 ^ 64
            if count < 200 {
                cubans[count] = commatize(diff)
            }
            count++
            if count == 100000 {
                cube100k = diff
                break
            }
        }
        cube1 = cube2
    }
    fmt.Println("The first 200 cuban primes are:-")
    for i := 0; i < 20; i++ {
        j := i * 10
        fmt.Printf("%9s\n", cubans[j : j+10]) // 10 per line say
    }
    fmt.Println("\nThe 100,000th cuban prime is", commatize(cube100k))
}