javascript

exercises

exercises.js
/**
 * 14.1 Number Fundamentals - Exercises
 *
 * Practice working with JavaScript numbers, special values, and precision.
 */

/**
 * Exercise 1: Safe Number Check
 *
 * Create a function that checks if a value is a "safe number" -
 * meaning it's a finite number (not NaN, not Infinity) and within
 * the safe integer range if it's an integer.
 *
 * @param {any} value - The value to check
 * @returns {boolean} - True if the value is a safe number
 *
 * Requirements:
 * - Return false for NaN
 * - Return false for Infinity and -Infinity
 * - Return false for non-number types
 * - Return true for finite numbers
 * - For integers, also check if they're safe integers
 */
function isSafeNumber(value) {
  // Your code here
}

// console.log(isSafeNumber(42));                    // true
// console.log(isSafeNumber(3.14));                  // true
// console.log(isSafeNumber(NaN));                   // false
// console.log(isSafeNumber(Infinity));              // false
// console.log(isSafeNumber('42'));                  // false
// console.log(isSafeNumber(2 ** 53));               // false (unsafe integer)
// console.log(isSafeNumber(2 ** 53 - 1));           // true (max safe integer)

/**
 * Exercise 2: Parse Mixed Input
 *
 * Create a function that extracts a number from various input formats.
 * Handle strings with units, currency, percentages, etc.
 *
 * @param {string} input - The input string to parse
 * @returns {number} - The extracted number, or NaN if not parseable
 *
 * Examples:
 * - "42px" → 42
 * - "$1,234.56" → 1234.56
 * - "50%" → 0.5
 * - "1.5em" → 1.5
 * - "-25.5" → -25.5
 */
function parseNumber(input) {
  // Your code here
}

// console.log(parseNumber('42px'));           // 42
// console.log(parseNumber('$1,234.56'));      // 1234.56
// console.log(parseNumber('50%'));            // 0.5
// console.log(parseNumber('1.5em'));          // 1.5
// console.log(parseNumber('-25.5'));          // -25.5
// console.log(parseNumber('hello'));          // NaN

/**
 * Exercise 3: Money Calculator
 *
 * Create a money calculator that handles arithmetic without
 * floating-point precision errors. Work internally with cents.
 *
 * @param {number} amount1 - First amount in dollars
 * @param {number} amount2 - Second amount in dollars
 * @param {string} operation - 'add', 'subtract', 'multiply', 'divide'
 * @returns {number} - Result in dollars (rounded to 2 decimal places)
 */
function moneyCalc(amount1, amount2, operation) {
  // Your code here
}

// console.log(moneyCalc(0.1, 0.2, 'add'));        // 0.3 (not 0.30000000000000004)
// console.log(moneyCalc(10.50, 3.25, 'subtract')); // 7.25
// console.log(moneyCalc(19.99, 3, 'multiply'));   // 59.97
// console.log(moneyCalc(100, 3, 'divide'));       // 33.33

/**
 * Exercise 4: Number Formatter
 *
 * Create a function that formats numbers in different styles.
 *
 * @param {number} num - The number to format
 * @param {string} style - 'currency', 'percent', 'compact', 'scientific'
 * @param {object} options - Optional settings (locale, currency)
 * @returns {string} - The formatted number
 */
function formatNumber(num, style, options = {}) {
  // Your code here
}

// console.log(formatNumber(1234.56, 'currency'));           // "$1,234.56"
// console.log(formatNumber(0.156, 'percent'));              // "15.6%"
// console.log(formatNumber(1500000, 'compact'));            // "1.5M"
// console.log(formatNumber(12345.678, 'scientific'));       // "1.23e+4"
// console.log(formatNumber(1234.56, 'currency', { currency: 'EUR' })); // "€1,234.56"

/**
 * Exercise 5: Base Converter
 *
 * Create a function that converts numbers between different bases.
 *
 * @param {string|number} value - The number to convert
 * @param {number} fromBase - The base to convert from (2-36)
 * @param {number} toBase - The base to convert to (2-36)
 * @returns {string} - The number in the target base
 */
function convertBase(value, fromBase, toBase) {
  // Your code here
}

// console.log(convertBase('1010', 2, 10));    // "10"
// console.log(convertBase('255', 10, 16));    // "ff"
// console.log(convertBase('ff', 16, 2));      // "11111111"
// console.log(convertBase('777', 8, 10));     // "511"
// console.log(convertBase('100', 10, 36));    // "2s"

/**
 * Exercise 6: Statistics Calculator
 *
 * Create a function that calculates basic statistics for an array of numbers.
 *
 * @param {number[]} numbers - Array of numbers
 * @returns {object} - Object with min, max, sum, mean, median, and range
 */
function calculateStats(numbers) {
  // Your code here
}

// console.log(calculateStats([1, 2, 3, 4, 5]));
// {
//   min: 1,
//   max: 5,
//   sum: 15,
//   mean: 3,
//   median: 3,
//   range: 4
// }

// console.log(calculateStats([10, 20, 30, 40]));
// {
//   min: 10,
//   max: 40,
//   sum: 100,
//   mean: 25,
//   median: 25,
//   range: 30
// }

/**
 * Exercise 7: Precision Comparator
 *
 * Create a function that compares two floating-point numbers
 * with a specified precision level.
 *
 * @param {number} a - First number
 * @param {number} b - Second number
 * @param {number} precision - Number of decimal places to consider
 * @returns {number} - -1 if a < b, 0 if equal, 1 if a > b
 */
function comparePrecision(a, b, precision = 10) {
  // Your code here
}

// console.log(comparePrecision(0.1 + 0.2, 0.3, 10));     // 0 (equal)
// console.log(comparePrecision(3.14159, 3.14160, 4));    // 0 (equal at 4 decimals)
// console.log(comparePrecision(3.14159, 3.14160, 5));    // -1 (a < b)
// console.log(comparePrecision(1.0001, 1.0000, 3));      // 0 (equal at 3 decimals)

/**
 * Exercise 8: BigInt Calculator
 *
 * Create a calculator that handles very large numbers using BigInt.
 * Support basic operations and factorial calculation.
 *
 * @param {string} operation - 'add', 'multiply', 'power', 'factorial'
 * @param {...string|number} args - Numbers as strings or numbers
 * @returns {string} - Result as a string
 */
function bigCalc(operation, ...args) {
  // Your code here
}

// console.log(bigCalc('add', '9007199254740991', '1000'));
// "9007199254741991"

// console.log(bigCalc('multiply', '123456789', '987654321'));
// "121932631112635269"

// console.log(bigCalc('power', '2', '100'));
// "1267650600228229401496703205376"

// console.log(bigCalc('factorial', '50'));
// "30414093201713378043612608166064768844377641568960512000000000000"

/**
 * Exercise 9: Range Generator
 *
 * Create a function that generates an array of numbers in a range,
 * with optional step and the ability to include decimal numbers.
 *
 * @param {number} start - Start of range (inclusive)
 * @param {number} end - End of range (inclusive)
 * @param {number} step - Step between numbers (default: 1)
 * @returns {number[]} - Array of numbers in the range
 */
function range(start, end, step = 1) {
  // Your code here
}

// console.log(range(1, 5));           // [1, 2, 3, 4, 5]
// console.log(range(0, 10, 2));       // [0, 2, 4, 6, 8, 10]
// console.log(range(5, 1, -1));       // [5, 4, 3, 2, 1]
// console.log(range(0, 1, 0.2));      // [0, 0.2, 0.4, 0.6, 0.8, 1]
// console.log(range(0.1, 0.5, 0.1));  // [0.1, 0.2, 0.3, 0.4, 0.5]

/**
 * Exercise 10: Number Validator
 *
 * Create a comprehensive number validator that checks various conditions.
 *
 * @param {any} value - The value to validate
 * @param {object} rules - Validation rules
 * @returns {object} - { valid: boolean, errors: string[] }
 *
 * Rules can include:
 * - type: 'integer' | 'float' | 'any'
 * - min: minimum value
 * - max: maximum value
 * - positive: boolean
 * - negative: boolean
 * - multipleOf: number
 */
function validateNumber(value, rules = {}) {
  // Your code here
}

// console.log(validateNumber(42, { type: 'integer', min: 0, max: 100 }));
// { valid: true, errors: [] }

// console.log(validateNumber(3.14, { type: 'integer' }));
// { valid: false, errors: ['Must be an integer'] }

// console.log(validateNumber(-5, { positive: true }));
// { valid: false, errors: ['Must be positive'] }

// console.log(validateNumber(7, { multipleOf: 3 }));
// { valid: false, errors: ['Must be a multiple of 3'] }

// console.log(validateNumber(150, { min: 0, max: 100 }));
// { valid: false, errors: ['Must be at most 100'] }

// ============================================
// SOLUTIONS
// ============================================

/*
// Solution 1
function isSafeNumber(value) {
    // Must be a number type
    if (typeof value !== 'number') return false;
    
    // Must be finite (not NaN, not Infinity)
    if (!Number.isFinite(value)) return false;
    
    // If it's an integer, check if it's a safe integer
    if (Number.isInteger(value)) {
        return Number.isSafeInteger(value);
    }
    
    // Finite float is safe
    return true;
}

// Solution 2
function parseNumber(input) {
    if (typeof input !== 'string') return NaN;
    
    // Remove currency symbols and commas
    let cleaned = input.replace(/[$€£,]/g, '');
    
    // Handle percentages
    if (cleaned.endsWith('%')) {
        const num = parseFloat(cleaned);
        return isNaN(num) ? NaN : num / 100;
    }
    
    // Parse the number (handles units like px, em, etc.)
    return parseFloat(cleaned);
}

// Solution 3
function moneyCalc(amount1, amount2, operation) {
    // Convert to cents (integer arithmetic)
    const cents1 = Math.round(amount1 * 100);
    const cents2 = Math.round(amount2 * 100);
    
    let result;
    switch (operation) {
        case 'add':
            result = cents1 + cents2;
            break;
        case 'subtract':
            result = cents1 - cents2;
            break;
        case 'multiply':
            result = Math.round(cents1 * amount2);
            break;
        case 'divide':
            result = Math.round(cents1 / amount2);
            break;
        default:
            return NaN;
    }
    
    return result / 100;
}

// Solution 4
function formatNumber(num, style, options = {}) {
    const locale = options.locale || 'en-US';
    const currency = options.currency || 'USD';
    
    switch (style) {
        case 'currency':
            return new Intl.NumberFormat(locale, {
                style: 'currency',
                currency: currency
            }).format(num);
            
        case 'percent':
            return new Intl.NumberFormat(locale, {
                style: 'percent',
                minimumFractionDigits: 1,
                maximumFractionDigits: 1
            }).format(num);
            
        case 'compact':
            return new Intl.NumberFormat(locale, {
                notation: 'compact',
                maximumFractionDigits: 1
            }).format(num);
            
        case 'scientific':
            return num.toExponential(2);
            
        default:
            return num.toString();
    }
}

// Solution 5
function convertBase(value, fromBase, toBase) {
    // Parse the input in the source base
    const decimal = parseInt(String(value), fromBase);
    
    if (isNaN(decimal)) {
        return 'Invalid input';
    }
    
    // Convert to target base
    return decimal.toString(toBase);
}

// Solution 6
function calculateStats(numbers) {
    if (!numbers || numbers.length === 0) {
        return null;
    }
    
    const sorted = [...numbers].sort((a, b) => a - b);
    const sum = numbers.reduce((acc, n) => acc + n, 0);
    const mean = sum / numbers.length;
    
    // Calculate median
    const mid = Math.floor(sorted.length / 2);
    const median = sorted.length % 2 === 0
        ? (sorted[mid - 1] + sorted[mid]) / 2
        : sorted[mid];
    
    return {
        min: sorted[0],
        max: sorted[sorted.length - 1],
        sum: sum,
        mean: mean,
        median: median,
        range: sorted[sorted.length - 1] - sorted[0]
    };
}

// Solution 7
function comparePrecision(a, b, precision = 10) {
    const factor = Math.pow(10, precision);
    const roundedA = Math.round(a * factor) / factor;
    const roundedB = Math.round(b * factor) / factor;
    
    if (roundedA < roundedB) return -1;
    if (roundedA > roundedB) return 1;
    return 0;
}

// Solution 8
function bigCalc(operation, ...args) {
    switch (operation) {
        case 'add':
            return (BigInt(args[0]) + BigInt(args[1])).toString();
            
        case 'multiply':
            return (BigInt(args[0]) * BigInt(args[1])).toString();
            
        case 'power':
            return (BigInt(args[0]) ** BigInt(args[1])).toString();
            
        case 'factorial':
            const n = BigInt(args[0]);
            let result = 1n;
            for (let i = 2n; i <= n; i++) {
                result *= i;
            }
            return result.toString();
            
        default:
            return 'Unknown operation';
    }
}

// Solution 9
function range(start, end, step = 1) {
    const result = [];
    
    // Determine precision for floating-point handling
    const stepDecimals = (step.toString().split('.')[1] || '').length;
    const startDecimals = (start.toString().split('.')[1] || '').length;
    const precision = Math.max(stepDecimals, startDecimals);
    const factor = Math.pow(10, precision);
    
    if (step > 0 && start <= end) {
        for (let i = start; i <= end + Number.EPSILON; i += step) {
            result.push(Math.round(i * factor) / factor);
        }
    } else if (step < 0 && start >= end) {
        for (let i = start; i >= end - Number.EPSILON; i += step) {
            result.push(Math.round(i * factor) / factor);
        }
    }
    
    return result;
}

// Solution 10
function validateNumber(value, rules = {}) {
    const errors = [];
    
    // Check if it's a number
    if (typeof value !== 'number' || Number.isNaN(value)) {
        return { valid: false, errors: ['Must be a valid number'] };
    }
    
    // Check type
    if (rules.type === 'integer' && !Number.isInteger(value)) {
        errors.push('Must be an integer');
    }
    
    // Check minimum
    if (rules.min !== undefined && value < rules.min) {
        errors.push(`Must be at least ${rules.min}`);
    }
    
    // Check maximum
    if (rules.max !== undefined && value > rules.max) {
        errors.push(`Must be at most ${rules.max}`);
    }
    
    // Check positive
    if (rules.positive && value <= 0) {
        errors.push('Must be positive');
    }
    
    // Check negative
    if (rules.negative && value >= 0) {
        errors.push('Must be negative');
    }
    
    // Check multiple of
    if (rules.multipleOf !== undefined) {
        const remainder = Math.abs(value % rules.multipleOf);
        if (remainder > Number.EPSILON && Math.abs(remainder - rules.multipleOf) > Number.EPSILON) {
            errors.push(`Must be a multiple of ${rules.multipleOf}`);
        }
    }
    
    return {
        valid: errors.length === 0,
        errors: errors
    };
}
*/
Exercises - JavaScript Tutorial | DeepML