VCHS Computer Science
Computer Science at Valley Catholic High School
Pages
Home
APCSA
APCSP
Ten Commandments
Jump
Positional Number System
Digit Separator:
None ('')
Comma (',')
Space (' ')
Positional Number System 1
Base:
Radix:
Digits:
Numeral:
Position Number System 2
Base:
Radix:
Digits:
Numeral:
Convert
Source Code
<!-- HTML --> Digit Separator: <select id="digit-separator"> <option value="">None ('')</option> <option value=",">Comma (',')</option> <option value=" " selected="">Space (' ')</option> </select> <p></p><h3>Positional Number System 1</h3><p></p> <p>Base: <span id="base-pns-1" value="tbd"></span> </p><p>Radix: <span id="radix-pns-1" value="tbd"></span> </p><p>Digits: <input id="digits-pns-1" style="width:24em" value="O I II III IIII V VI VII VIII VIIII"></p> <p>Numeral: <input id="numeral-pns-1" style="width:32em" value="IIII II"></p> <p></p><h3>Position Number System 2</h3><p></p> <p>Base: <span id="base-pns-2" value="tbd"></span> </p><p>Radix: <span id="radix-pns-2" value="tbd"></span> </p><p>Digits: <input id="digits-pns-2" style="width:24em" value="0 1"></p> <p>Numeral: <span id="numeral-pns-2"></span></p> <p> <button id="convert-button">Convert</button> <span id="error-message" style="color: red"></span> </p> <!-- JavaScript --> <script> const digitSeparatorElement = document.getElementById("digit-separator"); const digitsPNS1Element = document.getElementById("digits-pns-1"); const digitsPNS2Element = document.getElementById("digits-pns-2"); const basePNS1Element = document.getElementById("base-pns-1"); const basePNS2Element = document.getElementById("base-pns-2"); const radixPNS1Element = document.getElementById("radix-pns-1"); const radixPNS2Element = document.getElementById("radix-pns-2"); const numeralPNS1Element = document.getElementById("numeral-pns-1"); const numeralPNS2Element = document.getElementById("numeral-pns-2"); const convertButton = document.getElementById("convert-button"); const errorMessageElement = document.getElementById("error-message"); digitsPNS1Element.addEventListener("keydown", clearAnswer); digitsPNS2Element.addEventListener("keydown", clearAnswer); numeralPNS1Element.addEventListener("keydown", clearAnswer); convertButton.addEventListener("click", tryConvertNumber); function clearAnswer() { numeralPNS2Element.innerHTML = ""; basePNS1Element.innerHTML = "tbd"; basePNS2Element.innerHTML = "tbd"; } function tryConvertNumber() { try { errorMessageElement.innerHTML = ""; convertNumber(); } catch (e) { errorMessageElement.innerHTML = "<b>Error:</b> " + e.message; throw e; } } function convertNumber() { const sepIndex = digitSeparatorElement.selectedIndex; const digitSeparator = digitSeparatorElement.options[sepIndex].value; const numberInPNS1 = numeralPNS1Element.value.trim().split(digitSeparator); const digitsOfPNS1 = digitsPNS1Element.value.trim().split(digitSeparator); const digitsOfPNS2 = digitsPNS2Element.value.trim().split(digitSeparator); const NumberSystem1 = new PositionalNumberSystem({digits: digitsOfPNS1, separator: digitSeparator}); const NumberSystem2 = new PositionalNumberSystem({digits: digitsOfPNS2, separator: digitSeparator}); basePNS1Element.innerHTML = NumberSystem1.BASE; basePNS2Element.innerHTML = NumberSystem2.BASE; radixPNS1Element.innerHTML = NumberSystem1.RADIX; radixPNS2Element.innerHTML = NumberSystem2.RADIX; numeralPNS2Element.innerHTML = NumberSystem1.convertToNumberSystem(numberInPNS1, NumberSystem2); } function PositionalNumberSystem(config) { "use strict"; /* Private Values */ const SEPARATOR = getSeparator(config); const DIGITS = getDigits(config); const VALUES = getValues(DIGITS); const BASE = getBase(DIGITS); const RADIX = BASE; const DIGIT_ZERO = getZeroDigit(DIGITS); const DIGIT_ONE = getOneDigit(DIGITS); const NUMBER_ZERO = digitToNumber(DIGIT_ZERO); const NUMBER_ONE = digitToNumber(DIGIT_ONE); const incrementByOne = incrementByOne_Recursively; //const incrementByOne = incrementByOne_ByAddingTwoNumbers; const addTwoNumbers = addTwoNumbers_ByCountingFromLarger; //const addTwoNumbers = addTwoNumbers_UsingCarryArithmetic; const multiplyTwoNumbers = multiplyTwoNumbers_ByFactorSummation; //const multiplyTwoNumbers = multiplyTwoNumbers_FASTER; const convertToNumberSystem = convertToNumberSystem_ByCountingFromZero; //const convertToNumberSystem = convertToNumberSystem_FASTER; /* Public Properties */ this.ZERO = DIGIT_ZERO; this.ONE = DIGIT_ONE; this.DIGITS = DIGITS; this.VALUES = VALUES; this.BASE = BASE; this.RADIX = RADIX; /* Public Methods */ this.compare = function (m, n) { m = parseNumber(m); n = parseNumber(n); return compare(m, n); }; this.incrementByOne = function (n) { n = parseNumber(n); return incrementByOne(n).join(SEPARATOR); }; this.addTwoNumbers = function (m, n) { m = parseNumber(m); n = parseNumber(n); return addTwoNumbers(m, n).join(SEPARATOR); }; this.multiplyTwoNumbers = function (m, n) { m = parseNumber(m); n = parseNumber(n); return multiplyTwoNumbers(m, n).join(SEPARATOR); }; this.convertToNumberSystem = function (n, system) { n = parseNumber(n); return convertToNumberSystem(n, system).join(SEPARATOR); }; this.trimLeadingZeros = function (n) { n = parseNumber(n); return trimLeadingZeros(n).join(SEPARATOR); }; /* Finalization */ Object.freeze(this); /* Private Utility Functions */ function parseNumber(n) { let array; if (typeof n === "string") { array = n.split(SEPARATOR); } else if (typeof n === "object") { array = objectToArray(n); } else { throw Error("Invalid number: " + n); } return Object.freeze(array); } function objectToArray(object) { const length = object.length; const array = []; for (let i = 0; i < length; ++i) { let token = object[i]; if (typeof token !== "string") { token = token.toString(); } if (VALUES[token] === undefined) { throw Error("Invalid token: " + token); } array[i] = token; } return array; } function getSeparator(config) { const separator = config.separator; if (typeof separator === "string") { return separator; } else { return ""; } } function getDigits(config) { const digits = config.digits; let array; if (typeof digits === "string") { return Object.freeze(digits.split(SEPARATOR)); } else if (typeof digits === "object") { array = []; const len = digits.length; for (let i = 0; i < len; ++i) { array[i] = digits[i]; } return Object.freeze(array); } else { return Object.freeze([]); } } function getValues(digits) { const map = Object.create(null); const len = digits.length; for (let i = 0; i < len; ++i) { const digit = digits[i]; if (typeof digit !== "string") { throw Error("Digit is not a string: " + digit); } if (map[digit] !== undefined) { throw Error("Duplicate digit: " + digit); } map[digit] = i; } return Object.freeze(map); } function getBase(digits) { const len = digits.length; if (len < 2) { throw Error("Not enough digits: " + len); } return len; } function getRadix(digits) { const unique = Object.create(null); let count = 0; digits.forEach(function(string) { const length = string.length; for (let i = 0; i < length; ++i) { const digit = string[i]; if (unique[digit] === undefined) { ++count; } unique[digit] = true; } }); return count; } function getZeroDigit(arrayOfDigits) { return arrayOfDigits[0]; } function getOneDigit(arrayOfDigits) { return arrayOfDigits[1]; } function getSubarray(a, lower, upper) { const sub = [] for (let i = lower; i < upper; ++i) { sub.push(a[i]); } return Object.freeze(sub); } function addTwoSingleDigitNumbers(n1, n2) { return addThreeSingleDigitNumbers(NUMBER_ZERO, n1, n2); } function addThreeSingleDigitNumbers(n1, n2, n3) { let d1 = n1[0], d2 = n2[0], d3 = n3[0]; let iCarryValue = 0; let iOnesValue = VALUES[d1]; let qty = VALUES[d2] + VALUES[d3]; while (qty > 0) { if (++iOnesValue === BASE) { iOnesValue = 0; ++iCarryValue; } --qty; } return Object.freeze([DIGITS[iCarryValue], DIGITS[iOnesValue]]); } function digitToNumber(digit) { return Object.freeze([digit]); } function digitsToNumber(digits) { const length = digits.length; const number = []; for (let i = 0; i < length; ++i) { number[i] = digits[i]; } return Object.freeze(number); } function digitAt(number, index) { return number[index]; } function mostSignificantDigitOf(number) { return number[0]; } function leastSignificantDigitOf(number) { return number[number.length - 1]; } function trimLeadingZeros(n) { const upper = n.length; let lower = 0; while ((digitAt(n, lower) === DIGIT_ZERO) && (lower < upper)) { ++lower; } return getSubarray(n, lower, upper); } function incrementByOne_ByAddingTwoNumbers(n) { return addTwoNumbers(n, NUMBER_ONE); } function incrementByOne_Recursively(n) { const length = n.length; let left = length === 1 ? NUMBER_ZERO : getSubarray(n, 0, length - 1); const right = getSubarray(n, length - 1, length); const sum = addTwoSingleDigitNumbers(NUMBER_ONE, right); if (mostSignificantDigitOf(sum) === DIGIT_ONE) { left = incrementByOne(left); } return trimLeadingZeros(left.concat(leastSignificantDigitOf(sum))); } function addTwoNumbers_ByCountingFromLarger(m, n) { if (compare(n, m) > 0) { const larger = n; n = m; m = larger; } // Now m >= n. let count = NUMBER_ZERO; let sum = m; while (compare(count, n) !== 0) { sum = incrementByOne(sum); count = incrementByOne(count); } return sum; } function addTwoNumbers_UsingCarryArithmetic(m, n) { m = trimLeadingZeros(m); n = trimLeadingZeros(n); if (m.length < n.length) { const longer = n; n = m; m = longer; } // Now m.length >= n.length. let ans = [], carryDigit = DIGIT_ZERO, i = m.length, j = n.length; while (j > 0) { const sumOf3 = addThreeSingleDigitsNumbers( digitToNumber(carryDigit), digitToNumber(digitAt(m, --i)), digitToNumber(digitAt(n, --j)) ); carryDigit = mostSignificantDigitOf(sumOf3); ans.unshift(lastDigitOf(sumOf3)); } while (i > 0) { const sumOf2 = addTwoSingleDigitNumbers( digitToNumber(carryDigit), digitToNumber(digitAt(m, --i)) ); carryDigit = mostSignificantDigitOf(sumOf2); ans.unshift(lastDigitOf(sumOf2)); } if (carryDigit !== DIGIT_ZERO) { ans.unshift(carryDigit); } return Object.freeze(ans); } function areEqual(m, n) { return compare(m, n) === 0; } function isGreaterThan(m, n) { return compare(m, n) > 0; } function isGreaterThanOrEqual(m, n) { return compare(m, n) >= 0; } function isLessThan(m, n) { return compare(m, n) < 0; } function isLessThanOrEqual(m, n) { return compare(m, n) <= 0; } function compare(m, n) { m = trimLeadingZeros(m); n = trimLeadingZeros(n); const mLen = m.length; const nLen = n.length; if (mLen > nLen) return 1; else if (mLen < nLen) return -1; else { for (let i = 0; i < mLen; ++i) { const mDigValue = VALUES[digitAt(m, i)]; const nDigValue = VALUES[digitAt(n, i)]; if (mDigValue > nDigValue) return 1; else if (mDigValue < nDigValue) return -1; } return 0; } } function multiplyTwoNumbers_ByFactorSummation(m, n) { if (isGreaterThan(n, m)) { const bigger = n; n = m; m = bigger; } // Now m >= n. let count = NUMBER_ZERO, sum = NUMBER_ZERO; while (isLessThan(count, n)) { count = incrementByOne(count); sum = addTwoNumbers(sum, m); } return sum; } function convertToNumberSystem_ByCountingFromZero(n, numberSystem) { let mAsString = numberSystem.ZERO; let count = NUMBER_ZERO; while (isLessThan(count, n)) { count = incrementByOne(count); mAsString = numberSystem.incrementByOne(mAsString); } return mAsString.split(SEPARATOR); } } </script>
Newer Post
Older Post
Home