"""Randomize numbers by applying a random percentage variation.""" import contextlib import logging import re import secrets import sys logging.basicConfig(level=logging.INFO) # Use cryptographically secure random number generator _rng = secrets.SystemRandom() DEFAULT_MIN_PERCENTAGE = 1 DEFAULT_MAX_PERCENTAGE = 20 def randomize_numbers( numbers: list[float], min_percentage: float = DEFAULT_MIN_PERCENTAGE, max_percentage: float = DEFAULT_MAX_PERCENTAGE, ) -> list[float]: """Apply random percentage variation to a list of numbers.""" randomized_numbers = [] for number in numbers: percentage = _rng.uniform(min_percentage, max_percentage) / 100 if _rng.choice([True, False]): new_number = number + (number * percentage) else: new_number = number - (number * percentage) randomized_numbers.append(new_number) return randomized_numbers def parse_input(input_string: str) -> tuple[list[float], list[int]]: """Parse a string of numbers and return floats with decimal counts.""" # Replace commas with dots and remove non-numeric characters # except dots, commas, and digits cleaned_input = re.sub(r"[^\d.,\s]", "", input_string).replace(",", ".") # Split the cleaned input into individual numbers number_strings = cleaned_input.split() # Convert the number strings to floats numbers: list[float] = [] decimal_counts: list[int] = [] for num in number_strings: try: float_num = float(num) digits_count = len(num.split(".")[-1]) if "." in num else 0 numbers.append(float_num) decimal_counts.append(digits_count) except ValueError: continue return numbers, decimal_counts MIN_ARGS = 2 if __name__ == "__main__": if len(sys.argv) < MIN_ARGS: logging.info( "Usage: python random_digits.py ... " "[min_percentage max_percentage]" ) sys.exit(1) input_string = " ".join(sys.argv[1:]) numbers, decimal_counts = parse_input(input_string) if len(numbers) == 0: logging.error("No valid numbers provided.") sys.exit(1) min_percentage = DEFAULT_MIN_PERCENTAGE max_percentage = DEFAULT_MAX_PERCENTAGE try: if len(sys.argv) > len(numbers) + 1: with contextlib.suppress(ValueError): min_percentage = float(sys.argv[len(numbers) + 1]) if len(sys.argv) > len(numbers) + 2: with contextlib.suppress(ValueError): max_percentage = float(sys.argv[len(numbers) + 2]) randomized_numbers = randomize_numbers(numbers, min_percentage, max_percentage) formatted_numbers = [] for i, num in enumerate(randomized_numbers): format_str = f".{decimal_counts[i]}f" formatted_numbers.append(float(format(num, format_str))) logging.info(f"Original numbers: {numbers}") logging.info(f"Randomized numbers: {formatted_numbers}") except ValueError: logging.exception("Error processing numbers") logging.exception("Please provide valid numbers and percentages.") sys.exit(1)