Option Explicit

Private small As Variant, tens As Variant, big As Variant

Sub Main()
    small = Array("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", _
                  "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", _
                  "eighteen", "nineteen")
    tens = Array("twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety")
    big = Array("thousand", "million", "billion")

    Dim tmpInt As Long
    tmpInt = Val(InputBox("Gimme a number!", "NOW!", Trim$(Year(Now)) & IIf(Month(Now) < 10, "0", "") & _
                 Trim$(Month(Now)) & IIf(Day(Now) < 10, "0", "") & Trim$(Day(Now))))
    MsgBox int2Text$(tmpInt)
End Sub

Function int2Text$(number As Long)
    Dim num As Long, outP As String, unit As Integer
    Dim tmpLng1 As Long

    If 0 = number Then
        int2Text$ = "zero"
        Exit Function
    End If

    num = Abs(number)

    Do
        tmpLng1 = num Mod 100
        Select Case tmpLng1
            Case 1 To 19
                outP = small(tmpLng1 - 1) + " " + outP
            Case 20 To 99
                Select Case tmpLng1 Mod 10
                    Case 0
                        outP = tens((tmpLng1 \ 10) - 2) + " " + outP
                    Case Else
                        outP = tens((tmpLng1 \ 10) - 2) + "-" + small(tmpLng1 Mod 10) + " " + outP
                End Select
        End Select

        tmpLng1 = (num Mod 1000) \ 100
        If tmpLng1 Then
            outP = small(tmpLng1 - 1) + " hundred " + outP
        End If

        num = num \ 1000
        If num < 1 Then Exit Do

        tmpLng1 = num Mod 1000
        If tmpLng1 Then outP = big(unit) + " " + outP

        unit = unit + 1
    Loop

    If number < 0 Then outP = "negative " & outP

    int2Text$ = Trim$(outP)
End Function


Module Module1

    Sub Main()
        Dim i As Integer
        Console.WriteLine("Enter a number")
        i = Console.ReadLine()
        Console.WriteLine(words(i))
        Console.ReadLine()
    End Sub

    Function words(ByVal Number As Integer) As String
        Dim small() As String = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
         "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
         "eighteen", "nineteen"}
        Dim tens() As String = {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"}
        Select Case Number
            Case Is < 20
                words = small(Number)
            Case 20 To 99
                words = tens(Number \ 10) + " " + small(Number Mod 10)
            Case 100 To 999
                words = small(Number \ 100) + " hundred " + IIf(((Number Mod 100) <> 0), "and ", "") + words(Number Mod 100)
            Case 1000
                words = "one thousand"
        End Select
    End Function

End Module


const (
    small = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
    tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
    illions = ["", " thousand", " million", " billion", " trillion", " quadrillion", " quintillion"]
)

fn say(n i64) string {
    mut t := ''
    mut nn := n
    if n < 0 {
        t = "negative "
        // Note, for math.MinInt64 this leaves n negative.
        nn = -n
    }
    if nn < 20 {
        t += small[nn]
    }
    else if nn < 100 {
        t += tens[nn/10]
        s := nn % 10
        if s > 0 {
            t += "-" + small[s]
        }
    }
    else if nn < 1000 {
        t += small[nn/100] + " hundred"
        s := nn % 100
        if s > 0 {
            t += " " + say(s)
        }
    }
    else {
        // work right-to-left
        mut sx := ""
        for i := 0; nn > 0; i++ {
            p := nn % 1000
            nn /= 1000
            if p > 0 {
                mut ix := say(p) + illions[i]
                if sx != "" {
                    ix += " " + sx
                }
                sx = ix
            }
        }
        t += sx
    }
    return t
}

fn main(){
    mut nums := []i64{}
    nums = [i64(12), i64(1048576), i64(9e18), i64(-2), i64(0)]
    for n in nums {
        println(say(n))
    }
}


var small = ["zero", "one", "two", "three", "four", "five", "six",  "seven", "eight", "nine", "ten", "eleven",
             "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]

var tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]

var illions = ["", " thousand", " million", " billion"," trillion", " quadrillion", " quintillion"]

var say
say = Fn.new { |n|
    var t = ""
    if (n < 0) {
        t = "negative "
        n = -n
    }
    if (n < 20) {
        t = t + small[n]
    } else if (n < 100) {
        t = t + tens[(n/10).floor]
        var s = n % 10
        if (s > 0) t = t + "-" + small[s]
    } else if (n < 1000) {
        t = t + small[(n/100).floor] + " hundred"
        var s = n % 100
        System.write("") // guards against VM recursion bug
        if (s > 0) t = t + " " + say.call(s)
    } else {
        var sx = ""
        var i = 0
        while (n > 0) {
            var p = n % 1000
            n = (n/1000).floor
            if (p > 0) {
                System.write("") // guards against VM recursion bug
                var ix = say.call(p) + illions[i]
                if (sx != "") ix = ix + " " + sx
                sx = ix
            }
            i = i + 1
        }
        t = t + sx
    }
    return t
}

for (n in [12, 1048576, 9e18, -2, 0]) System.print(say.call(n))


code ChOut=8, CrLf=9, Text=12;

proc NumName(Dev, Num); \Output integer Num in prose to device Dev
int  Dev, Num;
int  OneTbl, TenTbl, ThoTbl, ThoPwr, I, Quot;

        proc Out999(N); \Output number in range 0..999 (0 does nothing)
        int  N;
        int  Huns, Tens, Ones;
        [Huns:= N/100;                          \0..9
        N:= rem(0);                             \0..99
        Tens:= N/10;                            \0..9
        Ones:= rem(0);                          \0..9
        if Huns # 0 then
                [Text(Dev, OneTbl(Huns));       \1..9
                Text(Dev, " hundred ")];
        if Tens >= 2 then
                [Text(Dev, TenTbl(Tens));
                if Ones # 0 then
                        [ChOut(Dev, ^-);  Text(Dev, OneTbl(Ones))];
                ]
        else    if N # 0 then Text(Dev, OneTbl(N));     \N = 1..19
        ];

[if Num = 0 then [Text(Dev, "zero");  return];
if Num < 0 then [Num:= -Num;  Text(Dev, "minus ")];

OneTbl:=[0, "one", "two", "three", "four",
        "five", "six", "seven", "eight", "nine",
        "ten", "eleven", "twelve", "thirteen", "fourteen",
        "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"];
TenTbl:=[0, 0, "twenty", "thirty", "forty",
        "fifty", "sixty", "seventy", "eighty", "ninety"];
ThoTbl:=[" billion ", " million ", " thousand "];

ThoPwr:= 1000000000;
for I:= 0 to 2 do
        [Quot:= Num/ThoPwr;
        Num:= rem(0);
        if Quot # 0 then
                [Out999(Quot);  Text(Dev, ThoTbl(I))];
        ThoPwr:= ThoPwr/1000;
        ];
Out999(Num);
];

[NumName(0, 0);  CrLf(0);
NumName(0, 13);  CrLf(0);
NumName(0, 789); CrLf(0);
NumName(0,  -604_001); CrLf(0);
NumName(0, 1_000_000); CrLf(0);
NumName(0, 1_234_567_890); CrLf(0);
]


var
   ns   =[1..20].chain([30..90,10]).walk(),
   names=T("one","two","three","four","five","six","seven","eight","nine",
           "ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen",
           "seventeen","eighteen","nineteen","twenty",
	   "thirty","forty","fifty","sixty","seventy","eighty","ninety"),
   hs    =T(  100,     1000,      1000000, 1000000000,1000000000000),
   hnames=T("hundred","thousand","million","billion", "trillion");

fcn numberToString(n){ // n>0
   fcn(n){
      if(100<=n<0d100_000_0000_000){
	 idx,h,name,r := hs.filter1n('>(n))-1, hs[idx], hnames[idx], n%h;
	 String(self.fcn(n/h),name,
	    if(r==0) "" else if(0<r<100) " and " else ", ",
	    self.fcn(r));
      }else if(0<n<=90){
	 idx,t,name,r := ns.filter1n('>(n))-1, ns[idx], names[idx], n-t;
	 String(name, if(0<r<10) "-" else " ", self.fcn(r));
      }else ""
   }(n).strip()  // sometimes there is a trailing space
}


V primes = [2, 3, 5, 7, 11, 13, 17, 19, 23]

F isPrime(n)
   I n < 2
      R 0B

   L(i) :primes
      I n == i
         R 1B
      I n % i == 0
         R 0B
      I i * i > n
         R 1B
   print(‘Oops, ’n‘  is too large’)
   R 0B

F init()
   V s = 24
   L s < 600
      I isPrime(s - 1) & s - 1 > :primes.last
         :primes.append(s - 1)
      I isPrime(s + 1) & s + 1 > :primes.last
         :primes.append(s + 1)
      s += 6

F nsmooth(n, size)
   assert(n C 2..521)
   assert(size >= 1)

   V bn = n
   V ok = 0B
   L(prime) :primes
      I bn == prime
         ok = 1B
         L.break
   assert(ok, ‘must be a prime number’)

   V ns = [BigInt(0)] * size
   ns[0] = 1

   [BigInt] next
   L(prime) :primes
      I prime > bn
         L.break
      next.append(prime)

   V indicies = [0] * next.len
   L(m) 1 .< size
      ns[m] = min(next)
      L(i) 0 .< indicies.len
         I ns[m] == next[i]
            indicies[i]++
            next[i] = :primes[i] * ns[indicies[i]]

   R ns

init()

L(p) primes
   I p >= 30
      L.break
   print(‘The first ’p‘ -smooth numbers are:’)
   print(nsmooth(p, 25))
   print()

L(p) primes[1..]
   I p >= 30
      L.break
   print(‘The 3000 to 3202 ’p‘ -smooth numbers are:’)
   print(nsmooth(p, 3002)[2999..])
   print()

L(p) [503, 509, 521]
   print(‘The 30000 to 3019 ’p‘ -smooth numbers are:’)
   print(nsmooth(p, 30019)[29999..])
   print()


#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>

void* xmalloc(size_t n) {
    void* ptr = malloc(n);
    if (ptr == NULL) {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    return ptr;
}

void* xrealloc(void* p, size_t n) {
    void* ptr = realloc(p, n);
    if (ptr == NULL) {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    return ptr;
}

bool is_prime(uint32_t n) {
    if (n == 2)
        return true;
    if (n < 2 || n % 2 == 0)
        return false;
    for (uint32_t p = 3; p * p <= n; p += 2) {
        if (n % p == 0)
            return false;
    }
    return true;
}

// Populates primes with the prime numbers between from and to and
// returns the number of primes found.
uint32_t find_primes(uint32_t from, uint32_t to, uint32_t** primes) {
    uint32_t count = 0, buffer_length = 16;
    uint32_t* buffer = xmalloc(sizeof(uint32_t) * buffer_length);
    for (uint32_t p = from; p <= to; ++p) {
        if (is_prime(p)) {
            if (count >= buffer_length) {
                uint32_t new_length = buffer_length * 2;
                if (new_length < count + 1)
                    new_length = count + 1;
                buffer = xrealloc(buffer, sizeof(uint32_t) * new_length);
                buffer_length = new_length;
            }
            buffer[count++] = p;
        }
    }
    *primes = buffer;
    return count;
}

void free_numbers(mpz_t* numbers, size_t count) {
    for (size_t i = 0; i < count; ++i)
        mpz_clear(numbers[i]);
    free(numbers);
}

// Returns an array containing first count n-smooth numbers
mpz_t* find_nsmooth_numbers(uint32_t n, uint32_t count) {
    uint32_t* primes = NULL;
    uint32_t num_primes = find_primes(2, n, &primes);
    mpz_t* numbers = xmalloc(sizeof(mpz_t) * count);
    mpz_t* queue = xmalloc(sizeof(mpz_t) * num_primes);
    uint32_t* index = xmalloc(sizeof(uint32_t) * num_primes);
    for (uint32_t i = 0; i < num_primes; ++i) {
        index[i] = 0;
        mpz_init_set_ui(queue[i], primes[i]);
    }
    for (uint32_t i = 0; i < count; ++i)
        mpz_init(numbers[i]);
    mpz_set_ui(numbers[0], 1);
    for (uint32_t i = 1; i < count; ++i) {
        for (uint32_t p = 0; p < num_primes; ++p) {
            if (mpz_cmp(queue[p], numbers[i - 1]) == 0)
                mpz_mul_ui(queue[p], numbers[++index[p]], primes[p]);
        }
        uint32_t min_index = 0;
        for (uint32_t p = 1; p < num_primes; ++p) {
            if (mpz_cmp(queue[min_index], queue[p]) > 0)
                min_index = p;
        }
        mpz_set(numbers[i], queue[min_index]);
    }
    free_numbers(queue, num_primes);
    free(primes);
    free(index);
    return numbers;
}

void print_nsmooth_numbers(uint32_t n, uint32_t begin, uint32_t count) {
    uint32_t num = begin + count;
    mpz_t* numbers = find_nsmooth_numbers(n, num);
    printf("%u: ", n);
    mpz_out_str(stdout, 10, numbers[begin]);
    for (uint32_t i = 1; i < count; ++i) {
        printf(", ");
        mpz_out_str(stdout, 10, numbers[begin + i]);
    }
    printf("\n");
    free_numbers(numbers, num);
}

int main() {
    printf("First 25 n-smooth numbers for n = 2 -> 29:\n");
    for (uint32_t n = 2; n <= 29; ++n) {
        if (is_prime(n))
            print_nsmooth_numbers(n, 0, 25);
    }
    printf("\n3 n-smooth numbers starting from 3000th for n = 3 -> 29:\n");
    for (uint32_t n = 3; n <= 29; ++n) {
        if (is_prime(n))
            print_nsmooth_numbers(n, 2999, 3);
    }
    printf("\n20 n-smooth numbers starting from 30,000th for n = 503 -> 521:\n");
    for (uint32_t n = 503; n <= 521; ++n) {
        if (is_prime(n))
            print_nsmooth_numbers(n, 29999, 20);
    }
    return 0;
}


#include <algorithm>
#include <iostream>
#include <vector>

std::vector<uint64_t> primes;
std::vector<uint64_t> smallPrimes;

template <typename T>
std::ostream &operator <<(std::ostream &os, const std::vector<T> &v) {
    auto it = v.cbegin();
    auto end = v.cend();

    os << '[';

    if (it != end) {
        os << *it;
        it = std::next(it);
    }

    for (; it != end; it = std::next(it)) {
        os << ", " << *it;
    }

    return os << ']';
}

bool isPrime(uint64_t value) {
    if (value < 2) return false;

    if (value % 2 == 0) return value == 2;
    if (value % 3 == 0) return value == 3;

    if (value % 5 == 0) return value == 5;
    if (value % 7 == 0) return value == 7;

    if (value % 11 == 0) return value == 11;
    if (value % 13 == 0) return value == 13;

    if (value % 17 == 0) return value == 17;
    if (value % 19 == 0) return value == 19;

    if (value % 23 == 0) return value == 23;

    uint64_t t = 29;
    while (t * t < value) {
        if (value % t == 0) return false;
        value += 2;

        if (value % t == 0) return false;
        value += 4;
    }

    return true;
}

void init() {
    primes.push_back(2);
    smallPrimes.push_back(2);

    uint64_t i = 3;
    while (i <= 521) {
        if (isPrime(i)) {
            primes.push_back(i);
            if (i <= 29) {
                smallPrimes.push_back(i);
            }
        }
        i += 2;
    }
}

std::vector<uint64_t> nSmooth(uint64_t n, size_t size) {
    if (n < 2 || n>521) {
        throw std::runtime_error("n must be between 2 and 521");
    }
    if (size <= 1) {
        throw std::runtime_error("size must be at least 1");
    }

    uint64_t bn = n;
    if (primes.cend() == std::find(primes.cbegin(), primes.cend(), bn)) {
        throw std::runtime_error("n must be a prime number");
    }

    std::vector<uint64_t> ns(size, 0);
    ns[0] = 1;

    std::vector<uint64_t> next;
    for (auto prime : primes) {
        if (prime > bn) {
            break;
        }
        next.push_back(prime);
    }

    std::vector<size_t> indicies(next.size(), 0);
    for (size_t m = 1; m < size; m++) {
        ns[m] = *std::min_element(next.cbegin(), next.cend());
        for (size_t i = 0; i < indicies.size(); i++) {
            if (ns[m] == next[i]) {
                indicies[i]++;
                next[i] = primes[i] * ns[indicies[i]];
            }
        }
    }

    return ns;
}

int main() {
    init();

    for (auto i : smallPrimes) {
        std::cout << "The first " << i << "-smooth numbers are:\n";
        std::cout << nSmooth(i, 25) << '\n';
        std::cout << '\n';
    }

    // there is not enough bits to fully represent the 3-smooth numbers
    for (size_t i = 0; i < smallPrimes.size(); i++) {
        if (i < 1) continue;
        auto p = smallPrimes[i];

        auto v = nSmooth(p, 3002);
        v.erase(v.begin(), v.begin() + 2999);

        std::cout << "The 30,000th to 30,019th " << p << "-smooth numbers are:\n";
        std::cout << v << '\n';
        std::cout << '\n';
    }

    return 0;
}


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

namespace NSmooth {
    class Program {
        static readonly List<BigInteger> primes = new List<BigInteger>();
        static readonly List<int> smallPrimes = new List<int>();

        static Program() {
            primes.Add(2);
            smallPrimes.Add(2);

            BigInteger i = 3;
            while (i <= 521) {
                if (IsPrime(i)) {
                    primes.Add(i);
                    if (i <= 29) {
                        smallPrimes.Add((int)i);
                    }
                }
                i += 2;
            }
        }

        static bool IsPrime(BigInteger value) {
            if (value < 2) return false;

            if (value % 2 == 0) return value == 2;
            if (value % 3 == 0) return value == 3;

            if (value % 5 == 0) return value == 5;
            if (value % 7 == 0) return value == 7;

            if (value % 11 == 0) return value == 11;
            if (value % 13 == 0) return value == 13;

            if (value % 17 == 0) return value == 17;
            if (value % 19 == 0) return value == 19;

            if (value % 23 == 0) return value == 23;

            BigInteger t = 29;
            while (t * t < value) {
                if (value % t == 0) return false;
                value += 2;

                if (value % t == 0) return false;
                value += 4;
            }

            return true;
        }

        static List<BigInteger> NSmooth(int n, int size) {
            if (n < 2 || n > 521) {
                throw new ArgumentOutOfRangeException("n");
            }
            if (size < 1) {
                throw new ArgumentOutOfRangeException("size");
            }

            BigInteger bn = n;
            bool ok = false;
            foreach (var prime in primes) {
                if (bn == prime) {
                    ok = true;
                    break;
                }
            }
            if (!ok) {
                throw new ArgumentException("must be a prime number", "n");
            }

            BigInteger[] ns = new BigInteger[size];
            ns[0] = 1;
            for (int i = 1; i < size; i++) {
                ns[i] = 0;
            }

            List<BigInteger> next = new List<BigInteger>();
            foreach (var prime in primes) {
                if (prime > bn) {
                    break;
                }
                next.Add(prime);
            }

            int[] indices = new int[next.Count];
            for (int i = 0; i < indices.Length; i++) {
                indices[i] = 0;
            }
            for (int m = 1; m < size; m++) {
                ns[m] = next.Min();
                for (int i = 0; i < indices.Length; i++) {
                    if (ns[m] == next[i]) {
                        indices[i]++;
                        next[i] = primes[i] * ns[indices[i]];
                    }
                }
            }

            return ns.ToList();
        }

        static void Println<T>(IEnumerable<T> nums) {
            Console.Write('[');

            var it = nums.GetEnumerator();
            if (it.MoveNext()) {
                Console.Write(it.Current);
            }
            while (it.MoveNext()) {
                Console.Write(", ");
                Console.Write(it.Current);
            }

            Console.WriteLine(']');
        }

        static void Main() {
            foreach (var i in smallPrimes) {
                Console.WriteLine("The first {0}-smooth numbers are:", i);
                Println(NSmooth(i, 25));
                Console.WriteLine();
            }
            foreach (var i in smallPrimes.Skip(1)) {
                Console.WriteLine("The 3,000 to 3,202 {0}-smooth numbers are:", i);
                Println(NSmooth(i, 3_002).Skip(2_999));
                Console.WriteLine();
            }
            foreach (var i in new int[] { 503, 509, 521 }) {
                Console.WriteLine("The 30,000 to 3,019 {0}-smooth numbers are:", i);
                Println(NSmooth(i, 30_019).Skip(29_999));
                Console.WriteLine();
            }
        }
    }
}


require "big"

def prime?(n) # P3 Prime Generator primality test
  return false unless (n | 1 == 3 if n < 5) || (n % 6) | 4 == 5
  sqrt_n = Math.isqrt(n)  # For Crystal < 1.2.0 use Math.sqrt(n).to_i
  pc = typeof(n).new(5)
  while pc <= sqrt_n
    return false if n % pc == 0 || n % (pc + 2) == 0
    pc += 6
  end
  true
end

def gen_primes(a, b)
    (a..b).select { |pc| pc if prime? pc }
end

def nsmooth(n, limit)
    raise "Exception(n or limit)" if n < 2 || n > 521 || limit < 1
    raise "Exception(must be a prime number: n)" unless prime? n

    primes = gen_primes(2, n)
    ns = [0.to_big_i] * limit
    ns[0] = 1.to_big_i
    nextp = primes[0..primes.index(n)].map { |prm| prm.to_big_i }

    indices = [0] * nextp.size
    (1...limit).each do |m|
        ns[m] = nextp.min
        (0...indices.size).each do |i|
            if ns[m] == nextp[i]
                indices[i] += 1
                nextp[i] = primes[i] * ns[indices[i]]
            end
        end
    end
    ns
end

gen_primes(2, 29).each do |prime|
    print "The first 25 #{prime}-smooth numbers are: \n"
    print nsmooth(prime, 25)
    puts
end
puts
gen_primes(3, 29).each do |prime|
    print "The 3000 to 3202 #{prime}-smooth numbers are: "
    print nsmooth(prime, 3002)[2999..]
    puts
end
puts
gen_primes(503, 521).each do |prime|
    print "The 30,000 to 30,019 #{prime}-smooth numbers are: \n"
    print nsmooth(prime, 30019)[29999..]
    puts
end


import std.algorithm;
import std.bigint;
import std.exception;
import std.range;
import std.stdio;

BigInt[] primes;
int[] smallPrimes;

bool isPrime(BigInt value) {
    if (value < 2) return false;

    if (value % 2 == 0) return value == 2;
    if (value % 3 == 0) return value == 3;

    if (value % 5 == 0) return value == 5;
    if (value % 7 == 0) return value == 7;

    if (value % 11 == 0) return value == 11;
    if (value % 13 == 0) return value == 13;

    if (value % 17 == 0) return value == 17;
    if (value % 19 == 0) return value == 19;

    if (value % 23 == 0) return value == 23;

    BigInt t = 29;
    while (t * t < value) {
        if (value % t == 0) return false;
        value += 2;

        if (value % t == 0) return false;
        value += 4;
    }

    return true;
}

// cache all primes up to 521
void init() {
    primes ~= BigInt(2);
    smallPrimes ~= 2;

    BigInt i = 3;
    while (i <= 521) {
        if (isPrime(i)) {
            primes ~= i;
            if (i <= 29) {
                smallPrimes ~= i.toInt;
            }
        }
        i += 2;
    }
}

BigInt[] nSmooth(int n, int size)
in {
    enforce(n >= 2 && n <= 521, "n must be between 2 and 521");
    enforce(size > 1, "size must be at least 1");
}
do {
    BigInt bn = n;
    bool ok = false;
    foreach (prime; primes) {
        if (bn == prime) {
            ok = true;
            break;
        }
    }
    enforce(ok, "n must be a prime number");

    BigInt[] ns;
    ns.length = size;
    ns[] = BigInt(0);
    ns[0] = 1;

    BigInt[] next;
    foreach(prime; primes) {
        if (prime > bn) {
            break;
        }
        next ~= prime;
    }

    int[] indicies;
    indicies.length = next.length;
    indicies[] = 0;
    foreach (m; 1 .. size) {
        ns[m] = next.reduce!min;
        foreach (i,v; indicies) {
            if (ns[m] == next[i]) {
                indicies[i]++;
                next[i] = primes[i] * ns[indicies[i]];
            }
        }
    }

    return ns;
}

void main() {
    init();

    foreach (i; smallPrimes) {
        writeln("The first ", i, "-smooth numbers are:");
        writeln(nSmooth(i, 25));
        writeln;
    }
    foreach (i; smallPrimes.drop(1)) {
        writeln("The 3,000th to 3,202 ", i, "-smooth numbers are:");
        writeln(nSmooth(i, 3_002).drop(2_999));
        writeln;
    }
    foreach (i; [503, 509, 521]) {
        writeln("The 30,000th to 30,019 ", i, "-smooth numbers are:");
        writeln(nSmooth(i, 30_019).drop(29_999));
        writeln;
    }
}


program N_smooth_numbers;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  System.Generics.Collections,
  Velthuis.BigIntegers;

var
  primes: TList<BigInteger>;
  smallPrimes: TList<Integer>;

function IsPrime(value: BigInteger): Boolean;
var
  v: BigInteger;
begin
  if value < 2 then
    exit(False);

  for v in [2, 3, 5, 7, 11, 13, 17, 19, 23] do
  begin
    if (value mod v) = 0 then
      exit(value = v);
  end;

  v := 29;

  while v * v < value do
  begin
    if (value mod v) = 0 then
      exit(False);
    inc(value, 2);
    if (value mod v) = 0 then
      exit(False);
    inc(v, 4);
  end;

  Result := True;
end;

function Min(values: TList<BigInteger>): BigInteger;
var
  value: BigInteger;
begin
  if values.Count = 0 then
    exit(0);

  Result := values[0];
  for value in values do
  begin
    if value < Result then
      result := value;
  end;
end;

function NSmooth(n, size: Integer): TList<BigInteger>;
var
  bn, p: BigInteger;
  ok: Boolean;
  i: Integer;
  next: TList<BigInteger>;
  indices: TList<Integer>;
  m: Integer;
begin
  Result := TList<BigInteger>.Create;
  if (n < 2) or (n > 521) then
    raise Exception.Create('Argument out of range: "n"');

  if (size < 1) then
    raise Exception.Create('Argument out of range: "size"');

  bn := n;
  ok := false;
  for p in primes do
  begin
    ok := bn = p;
    if ok then
      break;
  end;

  if not ok then
    raise Exception.Create('"n" must be a prime number');

  Result.Add(1);

  for i := 1 to size - 1 do
    Result.Add(0);

  next := TList<BigInteger>.Create;

  for p in primes do
  begin
    if p > bn then
      Break;
    next.Add(p);
  end;

  indices := TList<Integer>.Create;
  for i := 0 to next.Count - 1 do
    indices.Add(0);

  for m := 1 to size - 1 do
  begin
    Result[m] := Min(next);
    for i := 0 to indices.Count - 1 do
      if Result[m] = next[i] then
      begin
        indices[i] := indices[i] + 1;
        next[i] := primes[i] * Result[indices[i]];
      end;
  end;

  indices.Free;
  next.Free;
end;

procedure Init();
var
  i: BigInteger;
begin
  primes := TList<BigInteger>.Create;
  smallPrimes := TList<Integer>.Create;
  primes.Add(2);
  smallPrimes.Add(2);

  i := 3;
  while i <= 521 do
  begin
    if IsPrime(i) then
    begin

      primes.Add(i);
      if i <= 29 then
        smallPrimes.Add(Integer(i));
    end;
    inc(i, 2);
  end;

end;

procedure Println(values: TList<BigInteger>; CanFree: Boolean = False);
var
  value: BigInteger;
begin
  Write('[');
  for value in values do
    Write(value.ToString, ', ');
  Writeln(']'#10);

  if CanFree then
    values.Free;
end;

procedure Finish();
begin
  primes.Free;
  smallPrimes.Free;
end;

var
  p: Integer;
  ns: TList<BigInteger>;

const
  RANGE_3: array[0..2] of integer = (503, 509, 521);

begin
  Init;
  for p in smallPrimes do
  begin
    Writeln('The first ', p, '-smooth numbers are:');
    Println(NSmooth(p, 25), True);
  end;

  smallPrimes.Delete(0);
  for p in smallPrimes do
  begin
    Writeln('The 3,000 to 3,202 ', p, '-smooth numbers are:');
    ns := nSmooth(p, 3002);
    ns.DeleteRange(0, 2999);
    println(ns, True);
  end;

  for p in RANGE_3 do
  begin
    Writeln('The 3,000 to 3,019 ', p, '-smooth numbers are:');
    ns := nSmooth(p, 30019);
    ns.DeleteRange(0, 29999);
    println(ns, True);
  end;

  Finish;
  Readln;
end.


USING: deques dlists formatting fry io kernel locals make math
math.order math.primes math.text.english namespaces prettyprint
sequences tools.memory.private ;
IN: rosetta-code.n-smooth-numbers

SYMBOL: primes

: ns ( n -- seq )
    primes-upto [ primes set ] [ length [ 1 1dlist ] replicate ]
    bi ;

: enqueue ( n seq -- )
    [ primes get ] 2dip [ '[ _ * ] map ] dip [ push-back ] 2each
    ;

: next ( seq -- n )
    dup [ peek-front ] map infimum
    [ '[ dup peek-front _ = [ pop-front* ] [ drop ] if ] each ]
    [ swap enqueue ] [ nip ] 2tri ;

: next-n ( seq n -- seq )
    swap '[ _ [ _ next , ] times ] { } make ;

:: n-smooth ( n from to -- seq )
    n ns to next-n to from - 1 + tail* ;

:: show-smooth ( plo phi lo hi -- )
    plo phi primes-between [
        :> p lo commas lo ordinal-suffix hi commas hi
        ordinal-suffix p "%s%s through %s%s %d-smooth numbers: "
        printf p lo hi n-smooth [ pprint bl ] each nl
    ] each ;

: smooth-numbers-demo ( -- )
    2 29 1 25 show-smooth nl
    3 29 3000 3002 show-smooth nl
    503 521 30,000 30,019 show-smooth ;

MAIN: smooth-numbers-demo


package main

import (
    "fmt"
    "log"
    "math/big"
)

var (
    primes      []*big.Int
    smallPrimes []int
)

// cache all primes up to 521
func init() {
    two := big.NewInt(2)
    three := big.NewInt(3)
    p521 := big.NewInt(521)
    p29 := big.NewInt(29)
    primes = append(primes, two)
    smallPrimes = append(smallPrimes, 2)
    for i := three; i.Cmp(p521) <= 0; i.Add(i, two) {
        if i.ProbablyPrime(0) {
            primes = append(primes, new(big.Int).Set(i))
            if i.Cmp(p29) <= 0 {
                smallPrimes = append(smallPrimes, int(i.Int64()))
            }
        }
    }
}

func min(bs []*big.Int) *big.Int {
    if len(bs) == 0 {
        log.Fatal("slice must have at least one element")
    }
    res := bs[0]
    for _, i := range bs[1:] {
        if i.Cmp(res) < 0 {
            res = i
        }
    }
    return res
}

func nSmooth(n, size int) []*big.Int {
    if n < 2 || n > 521 {
        log.Fatal("n must be between 2 and 521")
    }
    if size < 1 {
        log.Fatal("size must be at least 1")
    }
    bn := big.NewInt(int64(n))
    ok := false
    for _, prime := range primes {
        if bn.Cmp(prime) == 0 {
            ok = true
            break
        }
    }
    if !ok {
        log.Fatal("n must be a prime number")
    }

    ns := make([]*big.Int, size)
    ns[0] = big.NewInt(1)
    var next []*big.Int
    for i := 0; i < len(primes); i++ {
        if primes[i].Cmp(bn) > 0 {
            break
        }
        next = append(next, new(big.Int).Set(primes[i]))
    }
    indices := make([]int, len(next))
    for m := 1; m < size; m++ {
        ns[m] = new(big.Int).Set(min(next))
        for i := 0; i < len(indices); i++ {
            if ns[m].Cmp(next[i]) == 0 {
                indices[i]++
                next[i].Mul(primes[i], ns[indices[i]])
            }
        }
    }
    return ns
}

func main() {
    for _, i := range smallPrimes {
        fmt.Printf("The first 25 %d-smooth numbers are:\n", i)
        fmt.Println(nSmooth(i, 25), "\n")
    }
    for _, i := range smallPrimes[1:] {
        fmt.Printf("The 3,000th to 3,202nd %d-smooth numbers are:\n", i)
        fmt.Println(nSmooth(i, 3002)[2999:], "\n")
    }
    for _, i := range []int{503, 509, 521} {
        fmt.Printf("The 30,000th to 30,019th %d-smooth numbers are:\n", i)
        fmt.Println(nSmooth(i, 30019)[29999:], "\n")
    }
}


import Data.Numbers.Primes (primes)
import Text.Printf (printf)

merge :: Ord a => [a] -> [a] -> [a]
merge [] b = b
merge a@(x:xs) b@(y:ys) | x < y     = x : merge xs b
                        | otherwise = y : merge a ys

nSmooth :: Integer -> [Integer]
nSmooth p = 1 : foldr u [] factors
 where
   factors = takeWhile (<=p) primes
   u n s = r
    where r = merge s (map (n*) (1:r))

main :: IO ()
main = do
  mapM_ (printf "First 25 %d-smooth:\n%s\n\n" <*> showTwentyFive) firstTenPrimes
  mapM_
    (printf "The 3,000 to 3,202 %d-smooth numbers are:\n%s\n\n" <*> showRange1)
    firstTenPrimes
  mapM_
    (printf "The 30,000 to 30,019 %d-smooth numbers are:\n%s\n\n" <*> showRange2)
    [503, 509, 521]
  where
    firstTenPrimes = take 10 primes
    showTwentyFive = show . take 25 . nSmooth
    showRange1 = show . ((<$> [2999 .. 3001]) . (!!) . nSmooth)
    showRange2 = show . ((<$> [29999 .. 30018]) . (!!) . nSmooth)


nsmooth=: dyad define  NB. TALLY nsmooth N
 factors=. x: [email protected]:>:&.:(p:inv) y
 smoothies=. , 1x
 result=. , i. 0x
 while. x > # result do.
  mn =. {. smoothies
  smoothies =. ({.~ (x <. #)) ~. /:~ (}. smoothies) , mn * factors
  result=. result , mn
 end.
)


import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

public class NSmoothNumbers {

    public static void main(String[] args) {
        System.out.printf("show the first 25 n-smooth numbers for n = 2 through n = 29%n");
        int max = 25;
        List<BigInteger> primes = new ArrayList<>();
        for ( int n = 2 ; n <= 29 ; n++ ) {
            if ( isPrime(n) ) {
                primes.add(BigInteger.valueOf(n));
                System.out.printf("The first %d %d-smooth numbers:%n", max, n);
                BigInteger[] humble = nSmooth(max, primes.toArray(new BigInteger[0]));
                for ( int i = 0 ; i < max ; i++ ) {
                    System.out.printf("%s ", humble[i]);
                }
                System.out.printf("%n%n");
            }
        }

        System.out.printf("show three numbers starting with 3,000 for n-smooth numbers for n = 3 through n = 29%n");
        int count = 3;
        max = 3000 + count - 1;
        primes = new ArrayList<>();
        primes.add(BigInteger.valueOf(2));
        for ( int n = 3 ; n <= 29 ; n++ ) {
            if ( isPrime(n) ) {
                primes.add(BigInteger.valueOf(n));
                System.out.printf("The %d through %d %d-smooth numbers:%n", max-count+1, max, n);
                BigInteger[] nSmooth = nSmooth(max, primes.toArray(new BigInteger[0]));
                for ( int i = max-count ; i < max ; i++ ) {
                    System.out.printf("%s ", nSmooth[i]);
                }
                System.out.printf("%n%n");
            }
        }

        System.out.printf("Show twenty numbers starting with 30,000 n-smooth numbers for n=503 through n=521%n");
        count = 20;
        max = 30000 + count - 1;
        primes = new ArrayList<>();
        for ( int n = 2 ; n <= 521 ; n++ ) {
            if ( isPrime(n) ) {
                primes.add(BigInteger.valueOf(n));
                if ( n >= 503 && n <= 521 ) {
                    System.out.printf("The %d through %d %d-smooth numbers:%n", max-count+1, max, n);
                    BigInteger[] nSmooth = nSmooth(max, primes.toArray(new BigInteger[0]));
                    for ( int i = max-count ; i < max ; i++ ) {
                        System.out.printf("%s ", nSmooth[i]);
                    }
                    System.out.printf("%n%n");
                }
            }
        }

    }

    private static final boolean isPrime(long test) {
        if ( test == 2 ) {
            return true;
        }
        if ( test % 2 == 0 ) return false;
        for ( long i = 3 ; i <= Math.sqrt(test) ; i += 2 ) {
            if ( test % i == 0 ) {
                return false;
            }
        }
        return true;
    }

    private static BigInteger[] nSmooth(int n, BigInteger[] primes) {
        int size = primes.length;
        BigInteger[] test = new BigInteger[size];
        for ( int i = 0 ; i < size ; i++ ) {
            test[i] = primes[i];
        }
        BigInteger[] results = new BigInteger[n];
        results[0] = BigInteger.ONE;

        int[] indexes = new int[size];
        for ( int i = 0 ; i < size ; i++ ) {
            indexes[i] = 0;
        }

        for ( int index = 1 ; index < n ; index++ ) {
            BigInteger min = test[0];
            for ( int i = 1 ; i < size ; i++ ) {
                min = min.min(test[i]);
            }
            results[index] = min;

            for ( int i = 0 ; i < size ; i++ ) {
                if ( results[index].compareTo(test[i]) == 0 ) {
                    indexes[i] = indexes[i] + 1;
                    test[i] = primes[i].multiply(results[indexes[i]]);
                }
            }
        }
        return results;
    }

}


F encode_neg_base(=n, b)
   I n == 0
      R ‘0’
   [Int] out
   L n != 0
      (n, V rem) = divmod(n, b)
      I rem < 0
         n++
         rem -= b
      out.append(rem)
   R reversed(out).map(String).join(‘’)

F decode_neg_base(nstr, b)
   I nstr == ‘0’
      R 0
   V total = 0
   L(ch) reversed(nstr)
      V i = L.index
      total += Int(ch) * b ^ i
   R total

print(‘Encode 10 as negabinary (expect 11110)’)
V result = encode_neg_base(10, -2)
print(result)
I decode_neg_base(result, -2) == 10
   print(‘Converted back to decimal’)
E
   print(‘Error converting back to decimal’)
print(‘Encode 146 as negaternary (expect 21102)’)
result = encode_neg_base(146, -3)
print(result)
I decode_neg_base(result, -3) == 146
   print(‘Converted back to decimal’)
E
   print(‘Error converting back to decimal’)
print(‘Encode 15 as negadecimal (expect 195)’)
result = encode_neg_base(15, -10)
print(result)
I decode_neg_base(result, -10) == 15
   print(‘Converted back to decimal’)
E
   print(‘Error converting back to decimal’)


using Primes

function nsmooth(N, needed)
    nexts, smooths = [BigInt(i) for i in 2:N if isprime(i)], [BigInt(1)]
    prim, count = deepcopy(nexts), 1
    indices = ones(Int, length(nexts))
    while count < needed
        x = minimum(nexts)
        push!(smooths, x)
        count += 1
        for j in 1:length(nexts)
            (nexts[j] <= x) && (nexts[j] = prim[j] * smooths[(indices[j] += 1)])
        end
    end
    return (smooths[end] > typemax(Int)) ? smooths : Int.(smooths)
end

function testnsmoothfilters()
    for i in filter(isprime, 1:29)
        println("The first 25 n-smooth numbers for n = $i are: ", nsmooth(i, 25))
    end
    for i in filter(isprime, 3:29)
        println("The 3000th through 3002nd ($i)-smooth numbers are: ", nsmooth(i, 3002)[3000:3002])
    end
    for i in filter(isprime, 503:521)
        println("The 30000th through 30019th ($i)-smooth numbers >= 30000 are: ", nsmooth(i, 30019)[30000:30019])
    end
end

testnsmoothfilters()


import java.math.BigInteger

var primes = mutableListOf<BigInteger>()
var smallPrimes = mutableListOf<Int>()

// cache all primes up to 521
fun init() {
    val two = BigInteger.valueOf(2)
    val three = BigInteger.valueOf(3)
    val p521 = BigInteger.valueOf(521)
    val p29 = BigInteger.valueOf(29)
    primes.add(two)
    smallPrimes.add(2)
    var i = three
    while (i <= p521) {
        if (i.isProbablePrime(1)) {
            primes.add(i)
            if (i <= p29) {
                smallPrimes.add(i.toInt())
            }
        }
        i += two
    }
}

fun min(bs: List<BigInteger>): BigInteger {
    require(bs.isNotEmpty()) { "slice must have at lease one element" }
    val it = bs.iterator()
    var res = it.next()
    while (it.hasNext()) {
        val t = it.next()
        if (t < res) {
            res = t
        }
    }
    return res
}

fun nSmooth(n: Int, size: Int): List<BigInteger> {
    require(n in 2..521) { "n must be between 2 and 521" }
    require(size >= 1) { "size must be at least 1" }

    val bn = BigInteger.valueOf(n.toLong())
    var ok = false
    for (prime in primes) {
        if (bn == prime) {
            ok = true
            break
        }
    }
    require(ok) { "n must be a prime number" }

    val ns = Array<BigInteger>(size) { BigInteger.ZERO }
    ns[0] = BigInteger.ONE
    val next = mutableListOf<BigInteger>()
    for (i in 0 until primes.size) {
        if (primes[i] > bn) {
            break
        }
        next.add(primes[i])
    }
    val indices = Array(next.size) { 0 }
    for (m in 1 until size) {
        ns[m] = min(next)
        for (i in indices.indices) {
            if (ns[m] == next[i]) {
                indices[i]++
                next[i] = primes[i] * ns[indices[i]]
            }
        }
    }

    return ns.toList()
}

fun main() {
    init()
    for (i in smallPrimes) {
        println("The first 25 $i-smooth numbers are:")
        println(nSmooth(i, 25))
        println()
    }
    for (i in smallPrimes.drop(1)) {
        println("The 3,000th to 3,202 $i-smooth numbers are:")
        println(nSmooth(i, 3_002).drop(2_999))
        println()
    }
    for (i in listOf(503, 509, 521)) {
        println("The 30,000th to 30,019 $i-smooth numbers are:")
        println(nSmooth(i, 30_019).drop(29_999))
        println()
    }
}


CHAR ARRAY digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!"

INT FUNC MyMod(INT a,b)
  IF b>=0 THEN
    RETURN (a MOD b)
  FI
RETURN (a-(b*(a/b)))

PROC Encode(INT n,base CHAR ARRAY res)
  INT i,d,len
  CHAR tmp

  IF base<-63 OR base>-1 THEN Break() FI
  IF n=0 THEN SAssign(res,"0") FI

  len=0
  WHILE n#0
  DO
    d=MyMod(n,base)
    n==/base
    IF d<0 THEN
      n==+1
      d==-base
    FI
    len==+1
    res(len)=digits(d+1)
  OD
  res(0)=len

  FOR i=1 to len/2
  DO
    tmp=res(i)
    res(i)=res(len-i+1)
    res(len-i+1)=tmp
  OD
RETURN

BYTE FUNC Index(CHAR ARRAY s CHAR c)
  BYTE i

  FOR i=1 TO s(0)
  DO
    IF s(i)=c THEN RETURN (i) FI
  OD
RETURN (0)

INT FUNC Decode(CHAR ARRAY s INT base)
  INT res,b,i,pos

  IF base<-63 OR base>-1 THEN Break() FI
  IF s(0)=1 AND s(1)='0 THEN RETURN (0) FI

  res=0
  b=1
  pos=s(0)
  WHILE pos>=1
  DO
    i=Index(digits,s(pos))-1
    res==+i*b
    b==*base
    pos==-1
  OD
RETURN (res)

PROC Test(INT n,base)
  CHAR ARRAY s(20)
  INT v

  Encode(n,base,s)
  PrintF("%I encoded in base %I is %S%E",n,base,s)
  v=Decode(s,base)
  PrintF("%S decoded in base %I is %I%E%E",s,base,v)
RETURN

PROC Main()
  INT v
  Test(10,-2)
  Test(146,-3)
  Test(15,-10)
  Test(-568,-63)
RETURN


with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

package Negative_Base_Numbers is

   subtype base_t is Long_Long_Integer range -62 .. -1;

   function Encode_Negative_Base
     (N : in Long_Long_Integer; Base : in base_t) return Unbounded_String;
   function Decode_Negative_Base
     (N : in Unbounded_String; Base : in base_t) return Long_Long_Integer;

end Negative_Base_Numbers;

with Ada.Text_IO;
package body Negative_Base_Numbers is

   Digit_Chars : constant String :=
     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

   --------------------------
   -- Encode_Negative_Base --
   --------------------------

   function Encode_Negative_Base
     (N : in Long_Long_Integer; Base : in base_t) return Unbounded_String
   is
      procedure swap (a, b : in out Character) is
         temp : Character := a;
      begin
         a := b;
         b := temp;
      end swap;

      Result    : Unbounded_String  := Null_Unbounded_String;
      Local_N   : Long_Long_Integer := N;
      Remainder : Long_Long_Integer;

   begin
      if Local_N = 0 then
         Result := To_Unbounded_String ("0");
      else
         while Local_N /= 0 loop
            Remainder := Local_N rem Base;
            Local_N   := Local_N / Base;
            if Remainder < 0 then
               Local_N   := Local_N + 1;
               Remainder := Remainder - Base;
            end if;
            Append (Result, Digit_Chars (Integer (Remainder + 1)));
         end loop;
      end if;

      declare
         Temp_Result : String   := To_String (Result);
         Low         : Positive := Temp_Result'First;
         High        : Positive := Temp_Result'Last;
      begin
         while Low < High loop
            swap (Temp_Result (Low), Temp_Result (High));
            Low  := Low + 1;
            High := High - 1;
         end loop;
         Result := To_Unbounded_String (Temp_Result);
      end;

      return Result;
   end Encode_Negative_Base;

   --------------------------
   -- Decode_Negative_Base --
   --------------------------

   function Decode_Negative_Base
     (N : in Unbounded_String; Base : in base_t) return Long_Long_Integer
   is
      Total : Long_Long_Integer := 0;
      bb    : Long_Long_Integer := 1;
      Temp  : String            := To_String (N);
   begin
      if Length (N) = 0 or else (Length (N) = 1 and Element (N, 1) = '0') then
         return 0;
      end if;

      for char of reverse Temp loop
         for J in Digit_Chars'Range loop
            if char = Digit_Chars (J) then
               Total := Total + Long_Long_Integer (J - 1) * bb;
               bb    := bb * Base;
            end if;
         end loop;
      end loop;

      return Total;
   end Decode_Negative_Base;

end Negative_Base_Numbers;

with Ada.Text_IO;           use Ada.Text_IO;
with Negative_Base_Numbers; use Negative_Base_Numbers;
with Ada.Strings.Fixed;     use Ada.Strings.Fixed;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

procedure Main is

   procedure driver (N : in Long_Long_Integer; B : in base_t) is
      package long_IO is new Integer_IO (Long_Long_Integer);
      use long_IO;

      ns     : Unbounded_String := Encode_Negative_Base (N, B);
      P      : Long_Long_Integer;
      Output : String (1 .. 12);

   begin
      Put (Item => N, Width => 12);
      Put (" encoded in base ");
      Put (Item => B, Width => 3);
      Put_Line (" = " & To_String (ns));

      Move
        (Source  => To_String (ns), Target => Output,
         Justify => Ada.Strings.Right);
      P := Decode_Negative_Base (ns, B);
      Put (Output & " decoded in base ");
      Put (Item => B, Width => 3);
      Put (" = ");
      Put (Item => P, Width => 1);
      New_Line (2);
   end driver;

begin
   driver (10, -2);
   driver (146, -3);
   driver (15, -10);
   driver (36_058, -62);
end Main;


ClearAll[GenerateSmoothNumbers]
GenerateSmoothNumbers[max_?Positive] := GenerateSmoothNumbers[max, 7]
GenerateSmoothNumbers[max_?Positive, maxprime_?Positive] :=
 Module[{primes, len, vars, body, endspecs, its, data},
  primes = Prime[Range[PrimePi[maxprime]]];
  len = Length[primes];
  If[max < Min[primes],
   {}
   ,
   vars = Table[Unique[], len];
   body = Times @@ (primes^vars);
   endspecs = Prepend[Most[primes^vars], 1];
   endspecs = FoldList[Times, endspecs];
   its = Transpose[{vars, ConstantArray[0, len], MapThread[[email protected][#1, max/#2] &, {primes, endspecs}]}];
   With[{b = body, is = its},
    data = Table[b, Evaluate[Sequence @@ is]];
    ];
   data = Sort[Flatten[data]];
   data
   ]
  ]
Take[GenerateSmoothNumbers[10^8, 2], 25]
Take[GenerateSmoothNumbers[200, 3], 25]
Take[GenerateSmoothNumbers[200, 5], 25]
Take[GenerateSmoothNumbers[200, 7], 25]
Take[GenerateSmoothNumbers[200, 11], 25]
Take[GenerateSmoothNumbers[200, 13], 25]
Take[GenerateSmoothNumbers[200, 17], 25]
Take[GenerateSmoothNumbers[200, 19], 25]
Take[GenerateSmoothNumbers[200, 23], 25]
Take[GenerateSmoothNumbers[200, 29], 25]
Take[GenerateSmoothNumbers[10^40, 3], {3000, 3002}]
Take[GenerateSmoothNumbers[10^15, 5], {3000, 3002}]
Take[GenerateSmoothNumbers[10^10, 7], {3000, 3002}]
Take[GenerateSmoothNumbers[10^7, 11], {3000, 3002}]
Take[GenerateSmoothNumbers[10^7, 13], {3000, 3002}]
Take[GenerateSmoothNumbers[10^6, 17], {3000, 3002}]
Take[GenerateSmoothNumbers[10^5, 19], {3000, 3002}]
Take[GenerateSmoothNumbers[10^5, 23], {3000, 3002}]
Take[GenerateSmoothNumbers[10^5, 29], {3000, 3002}]

s = Select[Range[10^5], FactorInteger /* Last /* First /* LessEqualThan[503]];
s[[30000 ;; 30019]]
s = Select[Range[10^5], FactorInteger /* Last /* First /* LessEqualThan[509]];
s[[30000 ;; 30019]]
s = Select[Range[10^5], FactorInteger /* Last /* First /* LessEqualThan[521]];
s[[30000 ;; 30019]]


import sequtils, strutils
import bignum

const N = 521

func initPrimes(): tuple[primes: seq[Int]; smallPrimes: seq[int]] =

  var sieve: array[2..N, bool]
  for n in 2..N:
    if not sieve[n]:
      for k in countup(n * n, N, n): sieve[k] = true

  for n, isComposite in sieve:
    if not isComposite:
      result.primes.add newInt(n)
      if n <= 29: result.smallPrimes.add n

# Cache all primes up to N.
let (Primes, SmallPrimes) = initPrimes()

proc nSmooth(n, size: Positive): seq[Int] =
  assert n in 2..N, "'n' must be between 2 and " & $N

  let bn = newInt(n)
  assert bn in Primes, "'n' must be a prime number"

  result.setLen(size)
  result[0] = newInt(1)

  var next: seq[Int]
  for prime in Primes:
    if prime > bn: break
    next.add prime

  var indices = newSeq[int](next.len)
  for m in 1..<size:
    result[m] = next[next.minIndex()]
    for i in 0..indices.high:
      if result[m] == next[i]:
        inc indices[i]
        next[i] = Primes[i] * result[indices[i]]

when isMainModule:

  for n in SmallPrimes:
    echo "The first ", n, "-smooth numbers are:"
    echo nSmooth(n, 25).join(" ")
    echo ""

  for n in SmallPrimes[1..^1]:
    echo "The 3000th to 3202th ", n, "-smooth numbers are:"
    echo nSmooth(n, 3002)[2999..^1].join(" ")
    echo ""

  for n in [503, 509, 521]:
    echo "The 30000th to 30019th ", n, "-smooth numbers are:"
    echo nSmooth(n, 30_019)[29_999..^1].join(" ")
    echo ""


program nSmoothNumbers(output);

const
	primeCount = 538;
	{$ifDef __GPC__} {$setLimit=3889} {$endIf}
	cardinalMax = 3888;

type
	cardinal = 0..cardinalMax;
	cardinals = set of cardinal;
	cardinalPositive = 1..cardinalMax;

	natural = 1..maxInt;

	primeIndex = 1..primeCount;
	list = array[primeIndex] of cardinal;

var
	prime: list;

{
	\brief performs prime factorization

	\param n the number to factorize
	\return list of exponents for a unique integer factorization using primes

	This function requires the global `prime` variable to be initialized.
}
function primeFactorization(n: natural): list;
var
	i: primeIndex;
	{
		Instead of writing `[1: 0; 2: 0; 3: 0; …]`, Extended Pascal permits us
		to use an “array completer” for all unspecified values.
	}
	result: list value [otherwise 0];
begin
	for i := 1 to primeCount do
	begin
		while n mod prime[i] = 0 do
		begin
			n := n div prime[i];
			result[i] := result[i] + 1
		end
	end;

	{ Nullify result if the utilized `prime` list was insufficient. }
	if n <> 1 then
	begin
		{ `array` literals need an explicit data type specification. }
		result := list[otherwise 0]
	end;

	{
		In a Pascal function definition there must be _one_ assignment to the
		(implicitly) declared variable bearing the same name as of the function.
		This will be returned function result.
	}
	primeFactorization := result
end;

{
	\brief returns whether a number is an n-smooth number

	\param smoothness the maximum permissible prime factor
	\param x the number to check
	\return whether \param x is smoothness-smooth
}
function isSmooth(
		protected smoothness: cardinalPositive;
		protected x: natural
	): Boolean;
	{
		Return set of non-one factors (i.e. non-zero exponent).

		Nesting this function permits most compilers to allocate memory
		for variables only if the function is actually needed.
	}
	function factorizationBases: cardinals;
	var
		exponent: list;
		i: primeIndex;
		result: cardinals value [];
	begin
		exponent := primeFactorization(x);

		for i := 1 to primeCount do
		begin
			if exponent[i] > 0 then
			begin
				result := result + [prime[i]]
			end
		end;

		factorizationBases := result
	end;
begin
	case smoothness of
		1:
		begin
			{
				The value `1` actually does not have a prime factorization, yet as per
				task specification “1 (unity) is always included in n‑smooth numbers.”
			}
			isSmooth := x = 1
		end;
		{ 2‑smooth numbers is an alias for powers of 2 (OEIS sequence A000079) }
		2:
		begin
			isSmooth := 2 pow round(ln(x) / ln(2)) = x
		end
		{ The `otherwise` catch-all-clause is an Extended Pascal extension. }
		otherwise
		begin
			isSmooth := card(factorizationBases - [0..smoothness]) = 0
			{
				`card` (“cardinality”) is an Extended Pascal extension.
				Testing `card(M) = 0` is equivalent to `M = []` (empty set).
			}
		end
	end
end;

{ === ancillary routines =============================================== }

{ This is just your regular Eratosthenes prime sieve. }
procedure sieve(var primes: cardinals);
var
	n: natural;
	i: integer;
	multiples: cardinals;
begin
	{ `1` is by definition not a prime number }
	primes := primes - [1];

	{ find the next non-crossed number }
	for n := 2 to cardinalMax do
	begin
		if n in primes then
		begin
			multiples := [];
			{ We do _not_ want to remove 1 * n. }
			i := 2 * n;
			while i in [n..cardinalMax] do
			begin
				multiples := multiples + [i];
				i := i + n
			end;

			primes := primes - multiples
		end
	end
end;

{ This procedure transforms a `set` to an `array`. }
procedure populatePrime;
var
	primes: cardinals value [1..cardinalMax];
	n: natural value 1;
	i: primeIndex value 1;
begin
	sieve(primes);

	for i := 1 to primeCount do
	begin
		repeat
		begin
			n := n + 1
		end
		until n in primes;

		prime[i] := n
	end
end;

{ ### MAIN ############################################################# }
var
	i: primeIndex value primeCount;
	candidate: natural;
	count: cardinal;
begin
	populatePrime;

	{ Show the first 25 n-smooth numbers […] }
	{ […] only prime [n] are to be used. }
	while prime[i] > 29 do
	begin
		i := i - 1
	end;

	{
		In Pascal, `for` loop limits are evaluated _once_,
		so this is perfectly legal:
	}
	for i := 1 to i do
	begin
		write(prime[i]:4, '-smooth: 1');

		count := 1; { `1` already listed. }
		candidate := 2;

		while count < 25 do
		begin
			if isSmooth(prime[i], candidate) then
			begin
				write(', ', candidate:1);
				count := count + 1
			end;
			candidate := candidate + 1
		end;

		writeLn
	end;

	{
		Note, in Pascal, the `for`‑loop iteration variable is not modified.
		At this point in the code, `i` (still) has the value after the `while`-loop.
		[This statement is not true, if a `goto` prematurely exited the `for`‑loop.]
	}

	writeLn;

	{ […] show three numbers starting with 3,000 […] }
	for i := 2 to i do
	begin
		write(prime[i]:4, '-smooth:');

		count := 0;
		candidate := 3000;

		while count < 3 do
		begin
			if isSmooth(prime[i], candidate) then
			begin
				write(' ', candidate:1);
				count := count + 1
			end;
			candidate := candidate + 1
		end;

		writeLn
	end;
end.


# Conversion to/from negative base numbers                                    #
# Note - no checks for valid bases or digits bases -2 .. -63 are handled      #
#        A-Z represent the digits 11 .. 35, a-z represent the digits 36 .. 61 #
#        the digit 62 is represented by a space                               #

#                               1         2         3         4         5         6          #
#                               01234567890123456789012345678901234567890123456789012        #
[]CHAR base digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz "[ AT 0 ];

# returns s decoded to an integer from the negative base b                   #
PRIO FROMNBASE = 9;
OP   FROMNBASE = ( STRING s, INT b )LONG INT:
     BEGIN
        LONG INT    result          := 0;
        LONG INT    base multiplier := 1;
        FOR d pos FROM UPB s BY -1 TO LWB s DO
            INT digit = IF   s[ d pos ] = " "
                        THEN 62
                        ELIF s[ d pos ] >= "a"
                        THEN ( ABS s[ d pos ] + 36 ) - ABS "a"
                        ELIF s[ d pos ] >= "A"
                        THEN ( ABS s[ d pos ] + 10 ) - ABS "A"
                        ELSE ABS s[ d pos ] - ABS "0"
                        FI;
            result          +:= base multiplier * digit;
            base multiplier *:= b
        OD;
        result
     END # FROMNBASE # ;
OP   FROMNBASE = ( CHAR c, INT b )LONG INT: STRING(c) FROMNBASE b;

# returns n encoded as a string in the negative base b #
PRIO TONBASE = 9;
OP   TONBASE = ( LONG INT n, INT b )STRING:
     BEGIN
        STRING   result := "";
        LONG INT v      := n;
        WHILE
            INT d := SHORTEN IF v < 0 THEN - ( ABS v MOD b ) ELSE v MOD b FI;
            v OVERAB b;
            IF d < 0
            THEN
                d -:= b;
                v +:= 1
            FI;
            base digits[ d ] +=: result;
            v /= 0
        DO SKIP OD;
        result
     END # TONBASE # ;

# tests the TONBASE and FROMNBASE operators #
PROC test n base = ( LONG INT number, INT base, STRING expected )VOID:
     BEGIN
        PROC expect = ( BOOL result )STRING: IF result THEN "" ELSE " INCORRECT" FI;
        STRING   encoded = number  TONBASE   base;
        LONG INT decoded = encoded FROMNBASE base;
        print( ( whole( number, 0 ), " encodes to: ", encoded ) );
        print( ( " base ", whole( base, 0 ), expect( encoded = expected ), newline ) );
        print( ( encoded, " decodes to: ", whole( decoded, 0 ) ) );
        print( ( " base ", whole( base, 0 ), expect( decoded = number   ), newline ) )
     END # test n base # ;

test n base(                    10,  -2,    "11110" );
test n base(                   146,  -3,    "21102" );
test n base(                    15, -10,      "195" );
# The defining document for ALGOL 68 spells the name "Algol 68" on the cover, though inside it is "ALGOL 68" #
# at the risk of "judging a language by it's cover", we use "Algol 68" as the name here...                   #
test n base( - LONG 36492107981104, -63, "Algol 68" )


use strict;
use warnings;
use feature 'say';
use ntheory qw<primes>;
use List::Util qw<min>;

#use bigint     # works, but slow
use Math::GMPz; # this module gives roughly 16x speed-up

sub smooth_numbers {
#    my(@m) = @_;                               # use with 'bigint'
    my @m = map { Math::GMPz->new($_) } @_;     # comment out to NOT use Math::GMPz
    my @s;
    push @s, [1] for 0..$#m;

    return sub {
    my $n = $s[0][0];
    $n = min $n, $s[$_][0] for 1..$#m;
    for (0..$#m) {
            shift @{$s[$_]} if $s[$_][0] == $n;
            push @{$s[$_]}, $n * $m[$_]
        }
        return $n
    }
}

sub abbrev {
    my($n) = @_;
    return $n if length($n) <= 50;
    substr($n,0,10) . "...(@{[length($n) - 2*10]} digits omitted)..." . substr($n, -10, 10)
}

my @primes = @{primes(10_000)};

my $start = 3000; my $cnt = 3;
for my $n_smooth (0..9) {
    say "\nFirst 25, and ${start}th through @{[$start+2]}nd $primes[$n_smooth]-smooth numbers:";
    my $s = smooth_numbers(@primes[0..$n_smooth]);
    my @S25;
    push @S25, $s->() for 1..25;
    say join ' ', @S25;

    my @Sm; my $c = 25;
    do {
        my $sn = $s->();
        push @Sm, abbrev($sn) if ++$c >= $start;
    } until @Sm == $cnt;
    say join ' ', @Sm;
}

$start = 30000; $cnt = 20;
for my $n_smooth (95..97) { # (503, 509, 521) {
    say "\n${start}th through @{[$start+$cnt-1]}th $primes[$n_smooth]-smooth numbers:";
    my $s = smooth_numbers(@primes[0..$n_smooth]);
    my(@Sm,$c);
    do {
        my $sn = $s->();
        push @Sm, $sn if ++$c >= $start;
    } until @Sm == $cnt;
    say join ' ', @Sm;
}


#include <stdio.h>

const char DIGITS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const int DIGITS_LEN = 64;

void encodeNegativeBase(long n, long base, char *out) {
    char *ptr = out;

    if (base > -1 || base < -62) {
        /* Bounds check*/
        out = "";
        return;
    }
    if (n == 0) {
        /* Trivial case */
        out = "0";
        return;
    }

    /* Convert the number into a string (in reverse) */
    while (n != 0) {
        long rem = n % base;
        n = n / base;
        if (rem < 0) {
            n++;
            rem = rem - base;
        }
        *ptr = DIGITS[rem];
        ptr++;
    }
    *ptr = 0;

    /* Reverse the current string to get the final result */
    ptr--;
    while (out < ptr) {
        char t = *out;
        *out = *ptr;
        *ptr = t;
        out++;
        ptr--;
    }
    return;
}

long decodeNegativeBase(const char* ns, long base) {
    long value, bb;
    int i;
    const char *ptr;

    if (base < -62 || base > -1) {
        /* Bounds check */
        return 0;
    }
    if (ns[0] == 0 || (ns[0] == '0' && ns[1] == 0)) {
        /* Trivial case */
        return 0;
    }

    /* Find the end of the string */
    ptr = ns;
    while (*ptr != 0) {
        ptr++;
    }

    /* Convert */
    value = 0;
    bb = 1;
    ptr--;
    while (ptr >= ns) {
        for (i = 0; i < DIGITS_LEN; i++) {
            if (*ptr == DIGITS[i]) {
                value = value + i * bb;
                bb = bb * base;
                break;
            }
        }
        ptr--;
    }

    return value;
}

void driver(long n, long b) {
    char buf[64];
    long value;

    encodeNegativeBase(n, b, buf);
    printf("%12d encoded in base %3d = %12s\n", n, b, buf);

    value = decodeNegativeBase(buf, b);
    printf("%12s decoded in base %3d = %12d\n", buf, b, value);

    printf("\n");
}

int main() {
    driver(10, -2);
    driver(146, -3);
    driver(15, -10);
    driver(12, -62);

    return 0;
}


with javascript_semantics
include mpfr.e

function nsmooth(integer n, integer needed)
-- note that n is a prime index, ie 1,2,3,4... for 2,3,5,7...
    sequence smooth = {mpz_init(1)},
             nexts = get_primes(-n),
             indices = repeat(1,n)
    for i=1 to n do nexts[i] = mpz_init(nexts[i]) end for
    for i=2 to needed do
        mpz x = mpz_init_set(mpz_min(nexts))
        smooth = append(smooth,x)
        for j=1 to n do
            if mpz_cmp(nexts[j],x)<=0 then
                indices[j] += 1
                mpz_mul_si(nexts[j],smooth[indices[j]],get_prime(j))
            end if
        end for
    end for
    return smooth
end function

function flat_str(sequence s)
    for i=1 to length(s) do s[i] = shorten(mpz_get_str(s[i]),ml:=10) end for
    return join(s," ")
end function

for n=1 to 10 do
    printf(1,"%d-smooth[1..25]: %s\n",{get_prime(n),flat_str(nsmooth(n, 25))})
end for
for n=1 to 10 do
    printf(1,"%d-smooth[3000..3002]: %s\n",{get_prime(n),flat_str(nsmooth(n, 3002)[3000..3002])})
end for
for n=96 to 98 do   -- primes 503, 509, and 521
    printf(1,"%d-smooth[30000..30019]: %s\n",{get_prime(n),flat_str(nsmooth(n, 30019)[30000..30019])})
end for


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

namespace NegativeBaseNumbers {
    class Program {
        const string DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

        static string EncodeNegativeBase(long n, int b) {
            if (b < -62 || b > -1) {
                throw new ArgumentOutOfRangeException("b");
            }
            if (n == 0) {
                return "0";
            }
            StringBuilder output = new StringBuilder();
            long nn = n;
            while (nn != 0) {
                int rem = (int)(nn % b);
                nn /= b;
                if (rem < 0) {
                    nn++;
                    rem -= b;
                }
                output.Append(DIGITS[rem]);
            }
            return new string(output.ToString().Reverse().ToArray());
        }

        static long DecodeNegativeBase(string ns, int b) {
            if (b < -62 || b > -1) {
                throw new ArgumentOutOfRangeException("b");
            }
            if (ns == "0") {
                return 0;
            }
            long total = 0;
            long bb = 1;
            for (int i = ns.Length - 1; i >= 0; i--) {
                char c = ns[i];
                total += DIGITS.IndexOf(c) * bb;
                bb *= b;
            }
            return total;
        }

        static void Main(string[] args) {
            List<Tuple<long, int>> nbl = new List<Tuple<long, int>>() {
                new Tuple<long, int>(10,-2),
                new Tuple<long, int>(146,-3),
                new Tuple<long, int>(15,-10),
                new Tuple<long, int>(-34025238427,-62),
            };
            foreach (var p in nbl) {
                string ns = EncodeNegativeBase(p.Item1, p.Item2);
                Console.WriteLine("{0,12} encoded in base {1,-3} = {2}", p.Item1, p.Item2, ns);
                long n = DecodeNegativeBase(ns, p.Item2);
                Console.WriteLine("{0,12} decoded in base {1,-3} = {2}", ns, p.Item2, n);
                Console.WriteLine();
            }
        }
    }
}


primes = [2, 3, 5, 7, 11, 13, 17, 19, 23]

def isPrime(n):
    if n < 2:
        return False

    for i in primes:
        if n == i:
            return True
        if n % i == 0:
            return False
        if i * i > n:
            return True
    print "Oops,", n, " is too large"

def init():
    s = 24
    while s < 600:
        if isPrime(s - 1) and s - 1 > primes[-1]:
            primes.append(s - 1)
        if isPrime(s + 1) and s + 1 > primes[-1]:
            primes.append(s + 1)
        s += 6

def nsmooth(n, size):
    if n < 2 or n > 521:
        raise Exception("n")
    if size < 1:
        raise Exception("n")

    bn = n
    ok = False
    for prime in primes:
        if bn == prime:
            ok = True
            break
    if not ok:
        raise Exception("must be a prime number: n")

    ns = [0] * size
    ns[0] = 1

    next = []
    for prime in primes:
        if prime > bn:
            break
        next.append(prime)

    indicies = [0] * len(next)
    for m in xrange(1, size):
        ns[m] = min(next)
        for i in xrange(0, len(indicies)):
            if ns[m] == next[i]:
                indicies[i] += 1
                next[i] = primes[i] * ns[indicies[i]]

    return ns

def main():
    init()

    for p in primes:
        if p >= 30:
            break
        print "The first", p, "-smooth numbers are:"
        print nsmooth(p, 25)
        print

    for p in primes[1:]:
        if p >= 30:
            break
        print "The 3000 to 3202", p, "-smooth numbers are:"
        print nsmooth(p, 3002)[2999:]
        print

    for p in [503, 509, 521]:
        print "The 30000 to 3019", p, "-smooth numbers are:"
        print nsmooth(p, 30019)[29999:]
        print

main()


#include <iomanip>
#include <iostream>
#include <tuple>
#include <vector>

const std::string DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

std::string encodeNegativeBase(int64_t n, int b) {
    if (b < -62 || b > -1) {
        throw std::runtime_error("Argument out of range: b");
    }
    if (n == 0) {
        return "0";
    }

    std::string output;
    int64_t nn = n;
    while (nn != 0) {
        int rem = nn % b;
        nn /= b;
        if (rem < 0) {
            nn++;
            rem -= b;
        }
        output += DIGITS[rem];
    }

    std::reverse(output.begin(), output.end());
    return output;
}

int64_t decodeNegativeBase(const std::string& ns, int b) {
    if (b < -62 || b > -1) {
        throw std::runtime_error("Argument out of range: b");
    }
    if (ns == "0") {
        return 0;
    }

    int64_t total = 0;
    int64_t bb = 1;

    for (auto it = ns.crbegin(); it != ns.crend(); it = std::next(it)) {
        auto ptr = std::find(DIGITS.cbegin(), DIGITS.cend(), *it);
        if (ptr != DIGITS.cend()) {
            auto idx = ptr - DIGITS.cbegin();
            total += idx * bb;
        }
        bb *= b;
    }
    return total;
}

int main() {
    using namespace std;

    vector<pair<int64_t, int>> nbl({
        make_pair(10, -2),
        make_pair(146, -3),
        make_pair(15, -10),
        make_pair(142961, -62)
        });

    for (auto& p : nbl) {
        string ns = encodeNegativeBase(p.first, p.second);
        cout << setw(12) << p.first << " encoded in base " << setw(3) << p.second << " = " << ns.c_str() << endl;

        int64_t n = decodeNegativeBase(ns, p.second);
        cout << setw(12) << ns.c_str() << " decoded in base " << setw(3) << p.second << " = " << n << endl;

        cout << endl;
    }

    return 0;
}


  [ behead 0 swap rot
    witheach
      [ 2dup < iff
          drop done
        nip nip
        i^ 1+ swap ] ]               is smallest   ( [ --> n n )

  [ stack ]                          is end.test   (   --> s   )

  [ ]'[ end.test put
    dup temp put
    ' [ 1 ]
    0 rot size of
    [ over end.test share do if done
      [] unrot
      dup dip
        [ witheach
            [ dip dup peek
              temp share i^ peek *
              rot swap join swap ] ]
      rot smallest
      dip
        [ 2dup peek 1+ unrot poke ]
      rot swap over
      -1 peek over = iff
        drop else join
      swap again ]
    drop
    end.test release
    temp release ]                   is smoothwith ( [ --> [   )

  [ ' [ 2 3 5 7 11 13 17 19 23 29 ]
    swap split drop ]                is primes     ( n --> [   )

  10 times
    [ i^ 1+ primes
      smoothwith [ size 25 = ]
      echo cr ]
  cr
  9 times
    [ i^ 2 + primes
      smoothwith [ size 3002 = ]
      -3 split nip echo cr ]


sub smooth-numbers (*@list) {
    cache my \Smooth := gather {
        my %i = (flat @list) Z=> (Smooth.iterator for ^@list);
        my %n = (flat @list) Z=> 1 xx *;

        loop {
            take my $n := %n{*}.min;

            for @list -> \k {
                %n{k} = %i{k}.pull-one * k if %n{k} == $n;
            }
        }
    }
}

sub abbrev ($n) {
   $n.chars > 50 ??
   $n.substr(0,10) ~ "...({$n.chars - 20} digits omitted)..." ~ $n.substr(* - 10) !!
   $n
}

my @primes = (2..*).grep: *.is-prime;

my $start = 3000;

for ^@primes.first( * > 29, :k ) -> $p {
    put join "\n", "\nFirst 25, and {$start}th through {$start+2}nd {@primes[$p]}-smooth numbers:",
    $(smooth-numbers(|@primes[0..$p])[^25]),
    $(smooth-numbers(|@primes[0..$p])[$start - 1 .. $start + 1]».&abbrev);
}

$start = 30000;

for 503, 509, 521 -> $p {
    my $i = @primes.first( * == $p, :k );
    put "\n{$start}th through {$start+19}th {@primes[$i]}-smooth numbers:\n" ~
    smooth-numbers(|@primes[0..$i])[$start - 1 .. $start + 18];
}


import std.stdio;

immutable DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

void main() {
    driver(10, -2);
    driver(146, -3);
    driver(15, -10);
    driver(13, -62);
}

void driver(long n, int b) {
    string ns = encodeNegBase(n, b);
    writefln("%12d encoded in base %3d = %12s", n, b, ns);

    long p = decodeNegBase(ns, b);
    writefln("%12s decoded in base %3d = %12d", ns, b, p);

    writeln;
}

string encodeNegBase(long n, int b) in {
    import std.exception : enforce;
    enforce(b <= -1 && b >= -62);
} body {
    if (n==0) return "0";
    char[] output;
    long nn = n;
    while (nn != 0) {
        int rem = nn % b;
        nn /= b;
        if (rem < 0) {
            nn++;
            rem -= b;
        }
        output ~= DIGITS[rem];
    }

    import std.algorithm : reverse;

    reverse(output);
    return cast(string) output;
}

long decodeNegBase(string ns, int b) in {
    import std.exception : enforce;
    enforce(b <= -1 && b >= -62);
} body {
    if (ns == "0") return 0;
    long total = 0;
    long bb = 1;
    foreach_reverse (c; ns) {
        foreach(i,d; DIGITS) {
            if (c==d) {
                total += i * bb;
                bb *= b;
                break;
            }
        }
    }
    return total;
}


/*REXX pgm computes&displays X n-smooth numbers; both X and N can be specified as ranges*/
numeric digits 200                               /*be able to handle some big numbers.  */
parse arg LOx HIx LOn HIn .                      /*obtain optional arguments from the CL*/
if LOx=='' | LOx==","  then LOx=  1              /*Not specified?  Then use the default.*/
if HIx=='' | HIx==","  then HIx= LOx + 24        /* "      "         "   "   "     "    */
if LOn=='' | LOn==","  then LOn=  2              /* "      "         "   "   "     "    */
if HIn=='' | HIn==","  then HIn= LOn + 27        /* "      "         "   "   "     "    */
call genP HIn                                    /*generate enough primes to satisfy HIn*/
@aList= ' a list of the ';              @thru= ' through '  /*literals used with a  SAY.*/

     do j=LOn  to  HIn;  if !.j==0  then iterate /*if not prime, then skip this number. */
     call smooth HIx,j;                 $=       /*invoke SMOOTH; initialize $  (list). */
                     do k=LOx  to HIx;  $= $ #.k /*append a  smooth number to  "  "   " */
                     end   /*k*/
     say center(@aList  th(LOx)  @thru  th(HIx)     ' numbers for' j"-smooth ",  130, "═")
     say strip($);                      say
     end   /*j*/                                 /* [↑]  the $ list has a leading blank.*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
genP: procedure expose @. !. #; parse arg x      /*#≡num of primes; @. ≡array of primes.*/
      @.=;      @.1=2; @.2=3; @.3=5; @.4=7; @.5=11; @.6=13; @.7=17; @.8=19; @.9=23;    #=9
      !.=0;     !.2=1; !.3=2; !.5=3; !.7=4; !.11=5; !.13=6; !.17=7; !.19=8; !.23=9
           do [email protected].#+6  by 2  until #>=x ;        if k//3==0    then iterate
           parse var  k  ''  -1  _;              if _==5       then iterate
                        do d=4  until @.d**2>k;  if k//@.d==0  then iterate k
                        end   /*d*/
           #= # + 1;    !.k= #;       @.#= k     /*found a prime, bump counter; assign @*/
           end  /*k*/;                return
/*──────────────────────────────────────────────────────────────────────────────────────*/
smooth: procedure expose @. !. #.; parse arg y,p /*obtain the arguments from the invoker*/
        if p==''  then p= 3                      /*Not specified? Then assume Hamming #s*/
        n= !.p                                   /*the number of primes being used.     */
        nn= n - 1;            #.=  0;    #.1= 1  /*an array of n-smooth numbers (so far)*/
        f.=  1                                   /*the indices of factors of a number.  */
                do j=2  for y-1;              _= f.1
                z= @.1 * #._
                             do k=2  for nn;  _= f.k;  v= @.k * #._;    if v<z  then z= v
                             end   /*k*/
                #.j= z
                             do d=1  for n;   _= f.d;  if @.d * #._==z  then f.d= f.d + 1
                             end   /*d*/
                end   /*j*/;                  return
/*──────────────────────────────────────────────────────────────────────────────────────*/
th: parse arg th; return th || word('th st nd rd', 1+(th//10)*(th//100%10\==1)*(th//10<4))


//I provide 2 fuctions D2N takes a radix and an integer returning a sequence of integers
//                     N2D takse a radix and a sequence of integers returning an integer
//Note that the radix may be either positive or negative.  Nigel Galloway, May 10th., 2019
let D2N n g=if g=0 then seq[0] else Seq.unfold(fun g->let α,β=g/n,g%n in match (compare g 0,β) with
                                                                          (0,_)->None
                                                                         |(1,_) |(_,0)->Some(β,α)
                                                                         |_->Some(g-(α+1)*n,α+1)) g|>Seq.rev
let N2D n g=fst(Seq.foldBack(fun g (Σ,α)->(Σ+α*g,n*α)) g (0,1))


USING: formatting fry kernel make math math.combinators
math.extras math.functions math.parser sequences ;

: /mod* ( x y -- z w )
    [ /mod ] keep '[ [ 1 + ] dip _ abs + ] when-negative ;

: >nega ( n radix -- str )
    [ '[ _ /mod* # ] until-zero ] "" make reverse ;

: nega> ( str radix -- n )
    swap <reversed> [ ^ swap digit> * ] with map-index sum ;

: .round-trip ( n radix -- )
    dupd [ >nega ] keep 2dup 2dup nega>
    "%d_10 is %s_%d\n%s_%d is %d_10\n\n" printf ;

10 -2 146 -3 15 -10 [ .round-trip ] [email protected]


package main

import (
    "fmt"
    "log"
    "strings"
)

const digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

func reverse(bs []byte) []byte {
    for i, j := 0, len(bs)-1; i < len(bs)/2; i, j = i+1, j-1 {
        bs[i], bs[j] = bs[j], bs[i]
    }
    return bs
}

func encodeNegBase(n, b int64) (string, error) {
    if b < -62 || b > -1 {
        return "", fmt.Errorf("base must be between -62 and -1 inclusive")
    }
    if n == 0 {
        return "0", nil
    }
    var out []byte
    for n != 0 {
        rem := n % b
        n /= b
        if rem < 0 {
            n++
            rem -= b
        }
        out = append(out, digits[int(rem)])
    }
    reverse(out)
    return string(out), nil
}

func decodeNegBase(ns string, b int64) (int64, error) {
    if b < -62 || b > -1 {
        return 0, fmt.Errorf("base must be between -62 and -1 inclusive")
    }
    if ns == "0" {
        return 0, nil
    }
    total := int64(0)
    bb := int64(1)
    bs := []byte(ns)
    reverse(bs)
    for _, c := range bs {
        total += int64(strings.IndexByte(digits, c)) * bb
        bb *= b
    }
    return total, nil
}

func main() {
    numbers := []int64{10, 146, 15, -942, 1488588316238}
    bases := []int64{-2, -3, -10, -62, -62}
    for i := 0; i < len(numbers); i++ {
        n := numbers[i]
        b := bases[i]
        ns, err := encodeNegBase(n, b)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%13d encoded in base %-3d = %s\n", n, b, ns)
        n, err = decodeNegBase(ns, b)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%13s decoded in base %-3d = %d\n\n", ns, b, n)
    }
}


def prime?(n)                     # P3 Prime Generator primality test
  return n | 1 == 3 if n < 5      # n: 2,3|true; 0,1,4|false
  return false if n.gcd(6) != 1   # this filters out 2/3 of all integers
  sqrtN = Integer.sqrt(n)
  pc = -1                         # initial P3 prime candidates value
  until (pc += 6) > sqrtN         # is resgroup 1st prime candidate > sqrtN
    return false if n % pc == 0 || n % (pc + 2) == 0  # if n is composite
  end
  true
end

def gen_primes(a, b)
    (a..b).select { |pc| pc if prime? pc }
end

def nsmooth(n, limit)
    raise "Exception(n or limit)" if n < 2 || n > 521 || limit < 1
    raise "Exception(must be a prime number: n)" unless prime? n

    primes = gen_primes(2, n)
    ns = [0] * limit
    ns[0] = 1
    nextp = primes[0..primes.index(n)]

    indices = [0] * nextp.size
    (1...limit).each do |m|
        ns[m] = nextp.min
        (0...indices.size).each do |i|
            if ns[m] == nextp[i]
                indices[i] += 1
                nextp[i] = primes[i] * ns[indices[i]]
            end
        end
    end
    ns
end

gen_primes(2, 29).each do |prime|
    print "The first 25 #{prime}-smooth numbers are: \n"
    print nsmooth(prime, 25)
    puts
end
puts
gen_primes(3, 29).each do |prime|
    print "The 3000 to 3202 #{prime}-smooth numbers are: "
    print nsmooth(prime, 3002)[2999..-1]    # for ruby >= 2.6: (..)[2999..]
    puts
end
puts
gen_primes(503, 521).each do |prime|
    print "The 30,000 to 30,019 #{prime}-smooth numbers are: \n"
    print nsmooth(prime, 30019)[29999..-1]  # for ruby >= 2.6: (..)[29999..]
    puts
end


import Data.Char (chr, ord)
import Numeric (showIntAtBase)

-- The remainder and quotient of n/d, where the remainder is guaranteed to be
-- non-negative.  The divisor, d, is assumed to be negative.
quotRemP :: Integral a => a -> a -> (a, a)
quotRemP n d = let (q, r) = quotRem n d
               in if r < 0 then (q+1, r-d) else (q, r)

-- Convert the number n to base b, where b is assumed to be less than zero.
toNegBase :: Integral a => a -> a -> a
toNegBase b n = let (q, r) = quotRemP n b
                in if q == 0 then r else negate b * toNegBase b q + r

-- Convert n to a string, where n is assumed to be a base b number, with b less
-- than zero.
showAtBase :: (Integral a, Show a) => a -> a -> String
showAtBase b n = showIntAtBase (abs b) charOf n ""
  where charOf m | m < 10    = chr $ m + ord '0'
                 | m < 36    = chr $ m + ord 'a' - 10
                 | otherwise = '?'

-- Print a number in base b, where b is assumed to be less than zero.
printAtBase :: (Integral a, Show a) => a -> a -> IO ()
printAtBase b = putStrLn . showAtBase b . toNegBase b

main :: IO ()
main = do
  printAtBase (-2)  10
  printAtBase (-3)  146
  printAtBase (-10) 15
  printAtBase (-16) 107
  printAtBase (-36) 41371458


fn is_prime(n: u32) -> bool {
    if n < 2 {
        return false;
    }
    if n % 2 == 0 {
        return n == 2;
    }
    if n % 3 == 0 {
        return n == 3;
    }
    let mut p = 5;
    while p * p <= n {
        if n % p == 0 {
            return false;
        }
        p += 2;
        if n % p == 0 {
            return false;
        }
        p += 4;
    }
    true
}

fn find_primes(from: u32, to: u32) -> Vec<u32> {
    let mut primes: Vec<u32> = Vec::new();
    for p in from..=to {
        if is_prime(p) {
            primes.push(p);
        }
    }
    primes
}

fn find_nsmooth_numbers(n: u32, count: usize) -> Vec<u128> {
    let primes = find_primes(2, n);
    let num_primes = primes.len();
    let mut result = Vec::with_capacity(count);
    let mut queue = Vec::with_capacity(num_primes);
    let mut index = Vec::with_capacity(num_primes);
    for i in 0..num_primes {
        index.push(0);
        queue.push(primes[i] as u128);
    }
    result.push(1);
    for i in 1..count {
        for p in 0..num_primes {
            if queue[p] == result[i - 1] {
                index[p] += 1;
                queue[p] = result[index[p]] * primes[p] as u128;
            }
        }
        let mut min_index: usize = 0;
        for p in 1..num_primes {
            if queue[min_index] > queue[p] {
                min_index = p;
            }
        }
        result.push(queue[min_index]);
    }
    result
}

fn print_nsmooth_numbers(n: u32, begin: usize, count: usize) {
    let numbers = find_nsmooth_numbers(n, begin + count);
    print!("{}: {}", n, &numbers[begin]);
    for i in 1..count {
        print!(", {}", &numbers[begin + i]);
    }
    println!();
}

fn main() {
    println!("First 25 n-smooth numbers for n = 2 -> 29:");
    for n in 2..=29 {
        if is_prime(n) {
            print_nsmooth_numbers(n, 0, 25);
        }
    }
    println!();
    println!("3 n-smooth numbers starting from 3000th for n = 3 -> 29:");
    for n in 3..=29 {
        if is_prime(n) {
            print_nsmooth_numbers(n, 2999, 3);
        }
    }
    println!();
    println!("20 n-smooth numbers starting from 30,000th for n = 503 -> 521:");
    for n in 503..=521 {
        if is_prime(n) {
            print_nsmooth_numbers(n, 29999, 20);
        }
    }
}


func smooth_generator(primes) {
    var s = primes.len.of { [1] }
    {
        var n = s.map { .first }.min
        { |i|
            s[i].shift if (s[i][0] == n)
            s[i] << (n * primes[i])
        } * primes.len
        n
    }
}

for p in (primes(2,29)) {
    var g = smooth_generator(p.primes)
    say ("First 25 #{'%2d'%p}-smooth numbers: ", 25.of { g.run }.join(' '))
}

say ''

for p in (primes(3,29)) {
    var g = smooth_generator(p.primes)
    say ("3,000th through 3,002nd #{'%2d'%p}-smooth numbers: ", 3002.of { g.run }.last(3).join(' '))
}


import BigInt
import Foundation

extension BinaryInteger {
  @inlinable
  public var isPrime: Bool {
    if self == 0 || self == 1 {
      return false
    } else if self == 2 {
      return true
    }

    let max = Self(ceil((Double(self).squareRoot())))

    for i in stride(from: 2, through: max, by: 1) {
      if self % i == 0 {
        return false
      }
    }

    return true
  }
}

@inlinable
public func smoothN<T: BinaryInteger>(n: T, count: Int) -> [T] {
  let primes = stride(from: 2, to: n + 1, by: 1).filter({ $0.isPrime })
  var next = primes
  var indices = [Int](repeating: 0, count: primes.count)
  var res = [T](repeating: 0, count: count)

  res[0] = 1

  guard count > 1 else {
    return res
  }

  for m in 1..<count {
    res[m] = next.min()!

    for i in 0..<indices.count where res[m] == next[i] {
      indices[i] += 1
      next[i] = primes[i] * res[indices[i]]
    }
  }

  return res
}

for n in 2...29 where n.isPrime {
  print("The first 25 \(n)-smooth numbers are: \(smoothN(n: n, count: 25))")
}

print()

for n in 3...29 where n.isPrime {
  print("The 3000...3002 \(n)-smooth numbers are: \(smoothN(n: BigInt(n), count: 3002).dropFirst(2999).prefix(3))")
}

print()

for n in 503...521 where n.isPrime {
  print("The 30,000...30,019 \(n)-smooth numbers are: \(smoothN(n: BigInt(n), count: 30_019).dropFirst(29999).prefix(20))")
}


import java.util.List;
import java.util.Map;
import java.util.Objects;

public class NegativeBaseNumbers {
    private static final String DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    private static String encodeNegBase(long n, int b) {
        if (b < -62 || b > -1) throw new IllegalArgumentException("Parameter b is out of bounds");
        if (n == 0) return "0";
        StringBuilder out = new StringBuilder();
        long nn = n;
        while (nn != 0) {
            int rem = (int) (nn % b);
            nn /= b;
            if (rem < 0) {
                nn++;
                rem -= b;
            }
            out.append(DIGITS.charAt(rem));
        }
        out.reverse();
        return out.toString();
    }

    private static long decodeNegBase(String ns, int b) {
        if (b < -62 || b > -1) throw new IllegalArgumentException("Parameter b is out of bounds");
        if (Objects.equals(ns, "0")) return 0;
        long total = 0;
        long bb = 1;
        for (int i = ns.length() - 1; i >= 0; i--) {
            char c = ns.charAt(i);
            total += DIGITS.indexOf(c) * bb;
            bb *= b;
        }
        return total;
    }

    public static void main(String[] args) {
        List<Map.Entry<Long, Integer>> nbl = List.of(
                Map.entry(10L, -2),
                Map.entry(146L, -3),
                Map.entry(15L, -10),
                Map.entry(-4393346L, -62)
        );
        for (Map.Entry<Long, Integer> p : nbl) {
            String ns = encodeNegBase(p.getKey(), p.getValue());
            System.out.printf("%12d encoded in base %-3d = %s\n", p.getKey(), p.getValue(), ns);
            long n = decodeNegBase(ns, p.getValue());
            System.out.printf("%12s decoded in base %-3d = %d\n\n", ns, p.getValue(), n);
        }
    }
}


import "/math" for Int
import "/big" for BigInt, BigInts

// cache all primes up to 521
var smallPrimes = Int.primeSieve(521)
var primes = smallPrimes.map { |p| BigInt.new(p) }.toList

var nSmooth = Fn.new { |n, size|
    if (n < 2 || n > 521) Fiber.abort("n must be between 2 and 521")
    if (size < 1) Fiber.abort("size must be at least 1")
    var bn = BigInt.new(n)
    var ok = false
    for (prime in primes) {
        if (bn == prime) {
            ok = true
            break
        }
    }
    if (!ok) Fiber.abort("n must be a prime number")
    var ns = List.filled(size, null)
    ns[0] = BigInt.one
    var next = []
    for (i in 0...primes.count) {
        if (primes[i] > bn) break
        next.add(primes[i])
    }
    var indices = List.filled(next.count, 0)
    for (m in 1...size) {
        ns[m] = BigInts.min(next)
        for (i in 0...indices.count) {
            if (ns[m] == next[i]) {
                indices[i] = indices[i] + 1
                next[i] = primes[i] * ns[indices[i]]
            }
        }
    }
    return ns
}

smallPrimes = smallPrimes.where { |p| p <= 29 }
for (i in smallPrimes) {
    System.print("The first 25 %(i)-smooth numbers are:")
    System.print(nSmooth.call(i, 25))
    System.print()
}
for (i in smallPrimes.skip(1)) {
    System.print("The 3,000th to 3,202nd %(i)-smooth numbers are:")
    System.print(nSmooth.call(i, 3002)[2999..-1])
    System.print()
}
for (i in [503, 509, 521]) {
    System.print("The 30,000th to 30,019th %(i)-smooth numbers are:")
    System.print(nSmooth.call(i, 30019)[29999..-1])
    System.print()
}


def trunc: if . >= 0 then floor else -(-(.)|trunc) end;


function negbase(n, b)
    if n == 0 return "0" end
    out = IOBuffer()
    while n != 0
        n, r = divrem(n, b)
        if r < 0
            n += 1
            r -= b
        end
        print(out, r)
    end
    return reverse(String(out))
end

invnegbase(nst, b) = sum((ch - '0') * b ^ (i - 1) for (i, ch) in enumerate(reverse(nst)))

testset = Dict(
    (10, -2) => "11110",
    (143, -3) => "21102",
    (15, -10) => "195")

for ((num, base), rst) in testset
    encoded = negbase(num, base)
    decoded = invnegbase(encoded, base)
    println("\nencode $num in base $base:\n-> expected: $rst\n-> resulted: $encoded\n-> decoded: $decoded")
end


// version 1.1.2

const val DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

fun encodeNegBase(n: Long, b: Int): String {
    require(b in -62 .. -1)
    if (n == 0L) return "0"
    val out = mutableListOf<Char>()
    var nn = n
    while (nn != 0L) {
        var rem = (nn % b).toInt()
        nn /= b
        if (rem < 0) {
            nn++
            rem -= b
        }
        out.add(DIGITS[rem])
    }
    out.reverse()
    return out.joinToString("")
}

fun decodeNegBase(ns: String, b: Int): Long {
    require(b in -62 .. -1)
    if (ns == "0") return 0
    var total = 0L
    var bb = 1L
    for (c in ns.reversed()) {
        total += DIGITS.indexOf(c) * bb
        bb *= b
    }
    return total
}

fun main(args:Array<String>) {
    val nbl = listOf(10L to -2, 146L to -3, 15L to -10, -17596769891 to -62)
    for (p in nbl) {
        val ns = encodeNegBase(p.first, p.second)
        System.out.printf("%12d encoded in base %-3d = %s\n", p.first, p.second, ns)
        val n  = decodeNegBase(ns, p.second)
        System.out.printf("%12s decoded in base %-3d = %d\n\n", ns, p.second, n)
    }
}


var [const] BI=Import("zklBigNum");  // libGMP

fcn nSmooth(n,sz){	// --> List of big ints
   if(sz<1) throw(Exception.ValueError("size must be at least 1"));
   bn,primes,ns := BI(n), List(), List.createLong(sz);
   if(not bn.probablyPrime()) throw(Exception.ValueError("n must be prime"));
   p:=BI(1); while(p<n){ primes.append(p.nextPrime().copy()) }  // includes n
   ns.append(BI(1));
   next:=primes.copy();
   if(Void!=( z:=primes.find(bn)) ) next.del(z+1,*);

   indices:=List.createLong(next.len(),0);
   do(sz-1){
      ns.append( nm:=BI( next.reduce(fcn(a,b){ a.min(b) }) ));
      foreach i in (indices.len()){
         if(nm==next[i]){
	    indices[i]+=1;
	    next[i]=primes[i]*ns[indices[i]];
	 }
      }
   }
   ns
}


EncodeBase[number_,base_]:=Module[{
  out={},
  rem,n=number,b=base
 },
 While[
  n!=0,
  {n,rem}={Floor[Divide[n,b]],Mod[n,b]};
  If[
   rem<0,
   n+=1;
   rem-=b
  ];
  PrependTo[out,rem]
 ];
 out
];
DecodeBase[list_,base_]:=Total[list*base^Range[Length[list]-1,0,-1]];

Print[EncodeNegBase[10,-2],"=",DecodeBase[EncodeNegBase[10,-2],-2]];
Print[EncodeNegBase[146,-3],"=",DecodeBase[EncodeNegBase[146,-3],-3]];
Print[EncodeNegBase[15,-10],"=",DecodeBase[EncodeNegBase[15,-10],-10]];


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

CONST DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
TYPE String = ARRAY[0..63] OF CHAR;

PROCEDURE EncodeNegativeBase(n : LONGINT; base : LONGINT) : String;
    PROCEDURE Mod(a,b : LONGINT) : LONGINT;
    BEGIN
        RETURN a - (a / b) * b
    END Mod;

    PROCEDURE Swap(VAR a,b : CHAR);
    VAR t : CHAR;
    BEGIN
        t := a;
        a := b;
        b := t
    END Swap;
VAR
    ptr,idx : CARDINAL;
    rem : LONGINT;
    result : String;
BEGIN
    IF (base > -1) OR (base < -62) THEN
        RETURN result
    ELSIF n = 0 THEN
        result := "0"
    ELSE
        ptr := 0;
        WHILE n # 0 DO
            rem := Mod(n, base);
            n := n / base;
            IF rem < 0 THEN
                INC(n);
                rem := rem - base
            END;
            result[ptr] := DIGITS[rem];
            INC(ptr);
        END
    END;
    result[ptr] := 0C;

    idx := 0;
    DEC(ptr);
    WHILE idx < ptr DO
        Swap(result[idx], result[ptr]);
        INC(idx);
        DEC(ptr)
    END;

    RETURN result
END EncodeNegativeBase;

PROCEDURE DecodeNegativeBase(ns : String; base : LONGINT) : LONGINT;
VAR
    total,bb,i,j : LONGINT;
BEGIN
    IF (base < -62) OR (base > -1) THEN
        RETURN 0
    ELSIF (ns[0] = 0C) OR ((ns[0] = '0') AND (ns[1] = 0C)) THEN
        RETURN 0
    ELSE
        FOR i:=0 TO HIGH(ns) DO
            IF ns[i] = 0C THEN
                BREAK
            END
        END;
        DEC(i);

        total := 0;
        bb := 1;
        WHILE i >= 0 DO
            FOR j:=0 TO HIGH(DIGITS) DO
                IF ns[i] = DIGITS[j] THEN
                    total := total + j * bb;
                    bb := bb * base;
                    BREAK
                END
            END;
            DEC(i)
        END;
    END;
    RETURN total
END DecodeNegativeBase;

PROCEDURE Driver(n,b : LONGINT);
VAR
    ns,buf : String;
    p : LONGINT;
BEGIN
    ns := EncodeNegativeBase(n, b);
    FormatString("%12l encoded in base %3l = %12s\n", buf, n, b, ns);
    WriteString(buf);

    p := DecodeNegativeBase(ns, b);
    FormatString("%12s decoded in base %3l = %12l\n", buf, ns, b, p);
    WriteString(buf);

    WriteLn
END Driver;

BEGIN
    Driver(10, -2);
    Driver(146, -3);
    Driver(15, -10);
    Driver(-19425187910, -62);

    ReadChar
END NegativeBase.


import algorithm, sugar, tables

const
  Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  Values = collect(initTable):
             for i, c in Digits: {c: i}   # Maps the digits to their values in base 10.

type Number = object
  ## Representation of a number in any base.
  base: int
  value: string

func toBase(n, base: int): Number =
  ## Convert an integer into a number in base 'base'.
  assert base notin -1..1, "wrong value for base: " & $base
  if n == 0: return Number(base: base, value: "0")
  result.base = base
  var n = n
  while n != 0:
    var m = n mod base
    n = n div base
    if m < 0:
      inc m, abs(base)
      inc n
    result.value.add Digits[m]
  result.value.reverse()

func `$`(n: Number): string =
  ## String representation of a number.
  $n.value

func toInt(n: Number): int =
  ## Convert a number in some base into an integer in base 10.
  for d in n.value:
    result = n.base * result + Values[d]

when isMainModule:

  proc process(n, base: int) =
    let s = n.toBase(base)
    echo "The value ", n, " is encoded in base ", base, " as: ", s
    echo "and is decoded back in base 10 as: ", s.toInt
    echo ""

process(10, -2)
process(146, -3)
process(15, -10)

const Nim = Number(base: -62, value: "Nim")
echo "The string “Nim” is decoded from base -62 to base 10 as: ", Nim.toInt


/* REXX ---------------------------------------------------------------
* Adapt for ooRexx (use of now invalid variable names)
* and make it work for base -63 (Algol example)
*--------------------------------------------------------------------*/
Numeric Digits 20
digits='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz '
txt=' converted to base '
n=      10;  b= -2;  nb=nBase(n,b);  Say right(n,20) txt right(b,3) '---->' nb ok()
n=     146;  b= -3;  nb=nBase(n,b);  Say right(n,20) txt right(b,3) '---->' nb ok()
n=      15;  b=-10;  nb=nBase(n,b);  Say right(n,20) txt right(b,3) '---->' nb ok()
n=     -15;  b=-10;  nb=nBase(n,b);  Say right(n,20) txt right(b,3) '---->' nb ok()
n=       0;  b= -5;  nb=nBase(n,b);  Say right(n,20) txt right(b,3) '---->' nb ok()
n=-6284695;  b=-62;  nb=nBase(n,b);  Say right(n,20) txt right(b,3) '---->' nb ok()
n=-36492107981104; b=-63;nb=nBase(n,b); Say right(n,20) txt right(b,3) '---->' nb ok()
Exit

nBase: Procedure Expose digits
/*---------------------------------------------------------------------
* convert x (base 10) to result (base r)
*--------------------------------------------------------------------*/
  Parse arg x,r
  result=''
  Do While x\==0              /*keep Processing while  X  isn't zero.*/
    z=x//r
    x=x%r                     /*calculate remainder; calculate int ÷.*/
    If z<0 Then Do
      z=z-r                   /*subtract a negative  R  from  Z ?--+ */
      x=x+1                   /*bump  X  by one.                   ¦ */
      End
    result=substr(digits,z+1,1)result        /*prepend the new digit */
    End
  If result='' Then result=0
  Return result

pBase: Procedure Expose digits;
/*---------------------------------------------------------------------
* convert x (base r) to result (base 10)
*--------------------------------------------------------------------*/
  Parse arg x,r;
  result=0;
  p=0
  len=length(x)
  Do j=len by -1 For len            /*Process each of the X's digits */
    v=pos(substr(x,j,1),digits)-1   /*use digit's numeric value.     */
    result=result+v*r**p;           /*add it to result               */
    p=p+1                           /*bump power by 1                */
    End
  Return result

ok:
/*---------------------------------------------------------------------
* check back conversion
*--------------------------------------------------------------------*/
  back=pBase(nb,b)
  If back\=n  Then
    r='Error backward conversion results in' back
  Else
    r='ok'
  Return r


use strict;
use feature 'say';
use POSIX qw(floor);
use ntheory qw/fromdigits todigits/;

sub encode {
    my($n, $b) = @_;
    my @out;
    my $r = 0;

    while ($n) {
        $r = $n % $b;
        $n = floor $n/$b;
        $n += 1, $r -= $b if $r < 0;
        push @out, todigits($r, -$b) || 0;
    }
    join '', reverse @out;
}

sub decode {
    my($s, $b) = @_;
    my $total = 0;
    my $i = 0;
    for my $c (reverse split '', $s) {
        $total += (fromdigits($c, -$b) * $b**$i);
        $i++;
    }
    $total
}

say ' 10 in base  -2: ', encode(10, -2);
say ' 15 in base -10: ', encode(15, -10);
say '146 in base  -3: ', encode(146, -3);
say '';
say  '11110 from base  -2: ', decode("11110", -2);
say  '21102 from base  -3: ', decode("21102", -3);
say  '  195 from base -10: ', decode("195",  -10);


with javascript_semantics
constant digits = "0123456789"&
                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"&
                  "abcdefghijklmnopqrstuvwxyz"

type base(integer b)
    return b<=-1 and b>=-length(digits)
end type

function encodeNegBase(atom n, base b)
    string res = iff(n?"":"0")
    while n!=0 do
        atom r = remainder(n,b)
        n = trunc(n/b)
        if r<0 then
            n += 1
            r -= b
        end if
        res &= digits[r+1]
    end while
    return reverse(res)
end function

function decodeNegBase(string ns, base b)
    atom total = 0,
         bb = 1
    for i=length(ns) to 1 by -1 do
        integer k = find(ns[i],digits)-1
        if k=-1 or k>-b then return "invalid digit" end if
        total += k*bb
        bb *= b
    end for
    return total
end function

                -- decimal, base, expected
constant tests = {{10,      -2,   "11110"},
                  {146,     -3,   "21102"},
                  {15,      -10,  "195"},
                  {-5795577,-62,  "Phix"}}

for i=1 to length(tests) do
    {atom n, atom b, string e} = tests[i]
    string ns = encodeNegBase(n, b)
    printf(1,"%9d in base %-3d is %6s\n", {n, b, ns})
    atom nn = decodeNegBase(ns, b)
    string ok = iff(ns=e and nn=n?""," ????")
    printf(1,"%9d <--------------'%s\n",{nn,ok})
end for