d8s-math 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
d8s_math/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ __version__ = "0.8.0"
2
+ __author__ = """Floyd Hightower"""
3
+ __email__ = "floyd.hightower27@gmail.com"
4
+
5
+ from .maths import *
d8s_math/maths.py ADDED
@@ -0,0 +1,674 @@
1
+ import collections
2
+ import functools
3
+ import itertools
4
+ import math
5
+ import numbers
6
+ from typing import Any, List, NamedTuple, Tuple, Union
7
+
8
+ import sympy
9
+
10
+
11
+ class integerTupleType(NamedTuple):
12
+ base: int
13
+ digits: Tuple[int, ...]
14
+
15
+
16
+ StrOrNumberType = Union[str, int, float, integerTupleType]
17
+
18
+
19
+ # TODO: write prime factorization function
20
+ # TODO: write a function to determine if a number is prime or not
21
+ # TODO: write function for degrees to radians and visa-versa (`math.radians(33.1)`)
22
+
23
+ # def percentOf(percent, number):
24
+ # """Return the given percent of the given number."""
25
+ # pass
26
+
27
+ # is / of = % / 100
28
+
29
+ # (I want to write functions for "is", "of", and "%" based on the above diagram)
30
+
31
+ # # TODO: may want to write a function to standardize percentages (e.g. 0.1 and 10 and '10' and '10%')
32
+
33
+
34
+ IntegerTuple = collections.namedtuple("IntegerTuple", ["base", "digits"])
35
+
36
+
37
+ def fibonacci_sequence(n: int) -> List[int]:
38
+ """Return the first n digits of the fibonacci sequence."""
39
+ nums = [fibonacci(i) for i in range(n)]
40
+ return nums
41
+
42
+
43
+ def fibonacci(n: int) -> int:
44
+ """Return the value of the Fibonacci sequence at index n."""
45
+ if n <= 1:
46
+ return 1
47
+ else:
48
+ return fibonacci(n - 1) + fibonacci(n - 2)
49
+
50
+
51
+ def number_closest(a, b, target):
52
+ """Return a or b, whichever is closest to the target."""
53
+ if abs(a - target) <= abs(b - target):
54
+ return a
55
+ else:
56
+ return b
57
+
58
+
59
+ def number_furthest(a, b, target):
60
+ """Return a or b, whichever is furthest to the target."""
61
+ if abs(a - target) >= abs(b - target):
62
+ return a
63
+ else:
64
+ return b
65
+
66
+
67
+ def cartesian_product(a: Any, *args: Any, repeat: int = 1):
68
+ """."""
69
+ return list(itertools.product(a, *args, repeat=repeat))
70
+
71
+
72
+ def sympy_symbol(symbol_name: str):
73
+ """."""
74
+ return sympy.symbols(symbol_name)
75
+
76
+
77
+ def equation_solve(equation: str, symbols: List[str]):
78
+ """."""
79
+ sympy_symbols = [sympy_symbol(symbol) for symbol in symbols]
80
+ map(eval, sympy_symbols)
81
+ solution = sympy.solve(equation)
82
+ return solution
83
+
84
+
85
+ def expression_explore(expression: str, symbol: str, start: int, end: int, step: int):
86
+ """."""
87
+ for i in range(start, end, step):
88
+ equation = f"Eq({expression}, {i})"
89
+ yield (i, equation_solve(equation, [symbol]))
90
+
91
+
92
+ def _hot_or_cold_encoder(items: list, default_value: int, changed_value: int, *, reverse: bool = False) -> List[list]:
93
+ results = []
94
+ unique_items = list(set(items))
95
+ sorted_items = sorted(unique_items, reverse=reverse)
96
+ max_index = len(unique_items)
97
+
98
+ for item in items:
99
+ encoded_result = [default_value for i in range(0, max_index)]
100
+ index_to_change = sorted_items.index(item)
101
+ encoded_result[index_to_change] = changed_value
102
+ results.append(encoded_result)
103
+
104
+ return results
105
+
106
+
107
+ def one_cold_encode(items: list, *, reverse: bool = False) -> List[list]:
108
+ return _hot_or_cold_encoder(items, 1, 0, reverse=reverse)
109
+
110
+
111
+ def one_hot_encode(items: list, *, reverse: bool = False) -> List[list]:
112
+ return _hot_or_cold_encoder(items, 0, 1, reverse=reverse)
113
+
114
+
115
+ def is_integer_tuple(possible_integer_tuple: Any) -> bool:
116
+ """."""
117
+ # I'm doing a more complex check rather than isinstance(possible_integer_tuple, IntegerTuple) because I was unable
118
+ # to get it consistently working when this function was used in other files... the current check works consistently
119
+ is_integer_tuple = (
120
+ isinstance(possible_integer_tuple, tuple)
121
+ and hasattr(possible_integer_tuple, "base")
122
+ and hasattr(possible_integer_tuple, "digits")
123
+ )
124
+ return is_integer_tuple
125
+
126
+
127
+ def string_to_number(string: str) -> Union[int, float]:
128
+ """Convert a number as a string into either an integer or float."""
129
+ if not isinstance(string, str):
130
+ return string
131
+
132
+ try:
133
+ return int(string)
134
+ except ValueError:
135
+ try:
136
+ return float(string)
137
+ except ValueError:
138
+ message = f"Unable to convert {string} to a number."
139
+ raise RuntimeError(message)
140
+
141
+
142
+ def first_arg_as_decimal(func):
143
+ """Convert the first argument to a number (either integer or float)."""
144
+
145
+ @functools.wraps(func)
146
+ def wrapper(*args, **kwargs):
147
+ first_arg = args[0]
148
+ other_args = args[1:]
149
+
150
+ if isinstance(first_arg, str):
151
+ first_arg = string_to_number(first_arg)
152
+ elif is_integer_tuple(first_arg):
153
+ first_arg = integer_tuple_to_decimal(first_arg)
154
+
155
+ return func(first_arg, *other_args, **kwargs)
156
+
157
+ return wrapper
158
+
159
+
160
+ def arguments_as_decimals(func):
161
+ """Convert all arguments to numbers (either integers or floats)."""
162
+
163
+ @functools.wraps(func)
164
+ def wrapper(*args, **kwargs):
165
+ new_args = []
166
+ for arg in args:
167
+ if isinstance(arg, str):
168
+ new_args.append(string_to_number(arg))
169
+ elif is_integer_tuple(arg):
170
+ decimal_arg = integer_tuple_to_decimal(arg)
171
+ new_args.append(decimal_arg)
172
+ else:
173
+ new_args.append(arg)
174
+ return func(*new_args, **kwargs)
175
+
176
+ return wrapper
177
+
178
+
179
+ @arguments_as_decimals
180
+ def decimal_to_gray_code(num: Union[str, int, float]) -> integerTupleType:
181
+ """Convert the given number to a gray code.
182
+
183
+ This function was inspired by the code here: https://en.wikipedia.org/wiki/Gray_code#Converting_to_and_from_Gray_code."""
184
+ gray_code = num ^ (num >> 1) # type: ignore[operator]
185
+ binary_gray_code = decimal_to_base(gray_code, 2)
186
+ return binary_gray_code
187
+
188
+
189
+ # TODO: should this function only take an integer tuple and not a string (e.g. '111') or int which will be intepreted as binary (e.g. 111) # noqa: E501
190
+ @arguments_as_decimals
191
+ def gray_code_to_decimal(num: integerTupleType) -> int:
192
+ """Convert the given number to a gray code.
193
+
194
+ This function was inspired by the code here: https://en.wikipedia.org/wiki/Gray_code#Converting_to_and_from_Gray_code."""
195
+ mask = num >> 1 # type: ignore[operator]
196
+ while mask != 0:
197
+ num = num ^ mask # type: ignore[operator, assignment]
198
+ mask = mask >> 1
199
+ return num # type: ignore[return-value]
200
+
201
+
202
+ def decimal_to_hex(decimal_number):
203
+ """."""
204
+ return hex(decimal_number)
205
+
206
+
207
+ def hex_to_decimal(hex):
208
+ """."""
209
+ return integer_to_decimal(hex, 16)
210
+
211
+
212
+ def roman_numeral_to_decimal(roman_numeral: str) -> int:
213
+ """."""
214
+ from number_tools.converters import roman_to_integer
215
+
216
+ result = roman_to_integer(roman_numeral)
217
+ return result
218
+
219
+
220
+ def decimal_to_roman_numeral(decimal_number) -> str:
221
+ """."""
222
+ from number_tools.converters import integer_to_roman
223
+
224
+ result = integer_to_roman(decimal_number)
225
+ return result
226
+
227
+
228
+ def integer_tuple_to_decimal(integer_tuple: integerTupleType) -> int:
229
+ """Return the decimal form of the given number (represented as an integer tuple)."""
230
+ decimal_number = 0
231
+
232
+ # flip the digits (so the smallest 'place' is first)
233
+ flipped_digits = reversed(integer_tuple.digits)
234
+ for index, num in enumerate(flipped_digits):
235
+ index_multiplier = integer_tuple.base**index
236
+ decimal_number += index_multiplier * num
237
+
238
+ return decimal_number
239
+
240
+
241
+ def integer_to_decimal(num: Union[str, int, float], base: int) -> int:
242
+ """Convert the number of the given base to a decimal number."""
243
+ number = str(num)
244
+ # TODO: the base is currently limited to numbers between 2 and 36... generalize this so that there are no such limitations # noqa: E501
245
+ converted_number = int(number, base=base)
246
+ return converted_number
247
+
248
+
249
+ def _base_converter_init(alphabet):
250
+ """."""
251
+ from baseconv import BaseConverter
252
+
253
+ converter = BaseConverter(alphabet)
254
+ return converter
255
+
256
+
257
+ def decimal_to_base(decimal_number: Union[str, int, float], base: int):
258
+ """Convert the decimal_number to the given base."""
259
+ if base == 1:
260
+ results = [1 for i in range(0, decimal_number)] # type: ignore[arg-type]
261
+ new_integer = IntegerTuple(base=base, digits=tuple(results))
262
+ return new_integer
263
+
264
+ results = []
265
+ max_value = base - 1
266
+
267
+ floor_divided_value = decimal_number // base # type: ignore[operator]
268
+ if floor_divided_value > max_value:
269
+ update = list(decimal_to_base(floor_divided_value, base).digits)
270
+ results.extend(update)
271
+ elif floor_divided_value != 0:
272
+ results.append(floor_divided_value) # type: ignore[arg-type]
273
+ results.append(decimal_number % base) # type: ignore[arg-type]
274
+
275
+ new_integer = IntegerTuple(base=base, digits=tuple(results))
276
+ return new_integer
277
+
278
+
279
+ # # TODO: I don't think the result_as_digit_list argument name is very descriptive; there is probably a better name for that argument # noqa: E501
280
+ # def decimal_to_base(
281
+ # decimal_number: Union[str, int, float],
282
+ # base: int,
283
+ # alphabet: str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
284
+ # result_as_digit_list: bool = False
285
+ # ):
286
+ # """Convert the decimal_number to the given base."""
287
+ # if base > len(alphabet):
288
+ # result_as_digit_list = True
289
+
290
+ # if result_as_digit_list:
291
+ # pass
292
+ # else:
293
+ # alphabet_for_base = alphabet[:base]
294
+
295
+ # if base == 1:
296
+ # result = alphabet_for_base[0] * decimal_number
297
+ # return result
298
+ # else:
299
+ # base_converter = _base_converter_init(alphabet_for_base)
300
+ # result = base_converter.encode(decimal_number)
301
+ # return result
302
+
303
+
304
+ def outer_division():
305
+ # not sure if this is a thing... I presume there is a corallary to outer_product
306
+ pass
307
+
308
+
309
+ # todo: provide an output variable
310
+ def outer_product(a: int, b: int, a_start: int = 1, b_start: int = 1):
311
+ """Return a two-dimensional array with the results of range(a_start, a+1) multiplied by range(b_start, b+1)."""
312
+ result = []
313
+
314
+ for i in range(a_start, a + 1):
315
+ result.append([i * j for j in range(b_start, b + 1)])
316
+
317
+ return result
318
+
319
+
320
+ def multiplication_table(a: int, b: int, a_start: int = 1, b_start: int = 1):
321
+ """."""
322
+ return outer_product(a, b, a_start=a_start, b_start=b_start)
323
+
324
+
325
+ def number_evenly_divides(a, b):
326
+ """Return True if a evenly divides b. Otherwise, return False."""
327
+ b_by_a_remainder = b % a
328
+ evenly_divides = b_by_a_remainder == 0
329
+ return evenly_divides
330
+
331
+
332
+ def number_evenly_divided_by(a, b):
333
+ """Return True if a is evenly divided by b. Otherwise, return False."""
334
+ evenly_divides = number_evenly_divides(b, a)
335
+ return evenly_divides
336
+
337
+
338
+ def fraction_examples(n=10, *, fractions_as_strings: bool = True):
339
+ """Create n fractions."""
340
+ from hypothesis.strategies import fractions
341
+ from hypothesis_data import hypothesis_get_strategy_results
342
+
343
+ fraction_object_examples = hypothesis_get_strategy_results(fractions, n=n)
344
+ if fractions_as_strings:
345
+ return [str(fraction) for fraction in fraction_object_examples]
346
+ else:
347
+ return fraction_object_examples
348
+
349
+
350
+ def iterable_differences(iterable):
351
+ """Find all of the possible differences of all possible orders of the given iterable."""
352
+ differences = []
353
+
354
+ iterable_permutations = permutations(iterable, length=len(iterable))
355
+ for permutation in iterable_permutations:
356
+ diff = permutation[0]
357
+ for i in permutation[1:]:
358
+ diff = diff - i
359
+ differences.append(diff)
360
+
361
+ return differences
362
+
363
+
364
+ def combinations(iterable, length=None):
365
+ """Return all possible combinations of the given length which can be created from the given iterable. If no length is given, we will find all combinations of all lengths for the given iterable.""" # noqa: E501
366
+ if length is None:
367
+ combos = []
368
+ for i in range(1, len(iterable) + 1):
369
+ combos.extend(combinations(iterable, length=i))
370
+ return combos
371
+ else:
372
+ return list(itertools.combinations(iterable, length))
373
+
374
+
375
+ def combinations_with_replacement(iterable, length=None):
376
+ """Return all possible combinations of the given length which can be created from the given iterable. If no length is given, we will find all combinations of all lengths for the given iterable.""" # noqa: E501
377
+ if length is None:
378
+ combos = []
379
+ for i in range(1, len(iterable) + 1):
380
+ combos.extend(combinations_with_replacement(iterable, length=i))
381
+ return combos
382
+ else:
383
+ return list(itertools.combinations_with_replacement(iterable, length))
384
+
385
+
386
+ def prod(iterable):
387
+ """Get the product of the iterable."""
388
+ import operator
389
+ from functools import reduce
390
+
391
+ # convert all of the items of the iterable to numbers
392
+ number_iterable = map(string_to_number, iterable)
393
+
394
+ return reduce(operator.mul, number_iterable, 1)
395
+
396
+
397
+ def permutations(iterable, length=None):
398
+ """Return all possible permutations of the given iterable. If no length is given, we will find all permutations of all lengths for the given iterable""" # noqa: E501
399
+ if length is None:
400
+ perms = []
401
+ for i in range(1, len(iterable) + 1):
402
+ perms.extend(permutations(iterable, length=i))
403
+ else:
404
+ perms = list(itertools.permutations(iterable, length))
405
+ return perms
406
+
407
+
408
+ def _split_fraction(fraction_string: str) -> Tuple[int, int]:
409
+ """Split up a fraction string and return a numerator and denominator."""
410
+ split_fraction_string = fraction_string.split("/")
411
+
412
+ if len(split_fraction_string) != 2:
413
+ message = f'Unable to handle the input "{fraction_string}" as a fraction. When providing a fraction, please separate the two numbers with a "/" character.' # noqa: E501
414
+ raise ValueError(message)
415
+ else:
416
+ numerator = int(split_fraction_string[0].strip())
417
+ denominator = int(split_fraction_string[1].strip())
418
+ return numerator, denominator
419
+
420
+
421
+ def _split_mixed_fraction(fraction_string):
422
+ """Split up a mixed fraction and return the whole number and the faction (e.g. "1 1/3"). This function requires that the whole number and fraction be separated by a space.""" # noqa: E501
423
+
424
+ split_fraction_string = fraction_string.split(" ")
425
+ if len(split_fraction_string) != 2:
426
+ print(
427
+ f'Unable to handle the input "{fraction_string}" as a mixed fraction. When providing a mixed fraction as an argument, please separate the whole number from the fraction with a space (and do not include spaces in the fraction).' # noqa: E501
428
+ )
429
+ return None, None
430
+ else:
431
+ # TODO: replace all spaces around the "/" character - not sure what this comment means, but I think I fixed it with the strip below... if this comment doesn't make any more sense to you, my future self, go ahead an remove it # noqa: E501
432
+ whole_number = int(split_fraction_string[0].strip())
433
+ fraction = split_fraction_string[1].strip()
434
+ return whole_number, fraction
435
+
436
+
437
+ def fraction_simplify(fraction_string):
438
+ """Simplify the fraction represented as a string."""
439
+ numerator, denominator = _split_fraction(fraction_string)
440
+ gcd_for_fraction = gcd(numerator, denominator)
441
+
442
+ return f"{int(numerator / gcd_for_fraction)}/{int(denominator / gcd_for_fraction)}"
443
+
444
+
445
+ def remainder(dividend, divisor):
446
+ return dividend % divisor
447
+
448
+
449
+ def floor(number):
450
+ return math.floor(number)
451
+
452
+
453
+ def ceiling(number):
454
+ return math.ceil(number)
455
+
456
+
457
+ def factorial(number):
458
+ return math.factorial(number)
459
+
460
+
461
+ def fraction_complex_to_mixed_fraction(fraction_string):
462
+ """Simplify the fraction represented as a string."""
463
+ simplified_fraction_string = fraction_simplify(fraction_string)
464
+ numerator, denominator = _split_fraction(simplified_fraction_string)
465
+
466
+ if numerator < denominator:
467
+ return f"{numerator}/{denominator}"
468
+ elif numerator == denominator:
469
+ return "1"
470
+ else:
471
+ fraction_remainder = remainder(numerator, denominator)
472
+ return f"{floor(numerator / denominator)} {fraction_remainder}/{denominator}"
473
+
474
+
475
+ def fraction_mixed_to_complex_fraction(fraction_string):
476
+ """Simplify the fraction represented as a string."""
477
+ whole_number, fraction = _split_mixed_fraction(fraction_string)
478
+
479
+ if not whole_number or not fraction:
480
+ return fraction_string
481
+
482
+ numerator, denominator = _split_fraction(fraction)
483
+
484
+ return f"{(whole_number * denominator) + numerator}/{denominator}"
485
+
486
+
487
+ def dot_product(item_a, item_b):
488
+ """Find the dot product for the two items. See https://en.wikipedia.org/wiki/Dot_product for more details."""
489
+ dot_product = 0
490
+
491
+ for i in zip(item_a, item_b):
492
+ dot_product += i[0] * i[1]
493
+
494
+ return dot_product
495
+
496
+
497
+ def percent(ratio):
498
+ """Return the ratio as a percentage."""
499
+ return round(ratio * 100, 2)
500
+
501
+
502
+ def percent_change(old_value: StrOrNumberType, new_value: StrOrNumberType) -> float:
503
+ """Return the change from the old_value to the new_value (as a percent of the old_value)."""
504
+ difference = new_value - old_value # type: ignore[operator]
505
+ diff_as_ratio = difference / old_value # type: ignore[operator]
506
+ return percent(diff_as_ratio)
507
+
508
+
509
+ @arguments_as_decimals
510
+ def gcd(number1, number2):
511
+ """Return the greatest common divisor."""
512
+ return math.gcd(number1, number2)
513
+
514
+
515
+ def ratio(number1, number2):
516
+ """Return the ratio of the two numbers in the form 1:2. For example, if given 5 and 10, this function would return "1:2". If given 2 and 20, this function would return "1:10".""" # noqa: E501
517
+ divisor = gcd(number1, number2)
518
+ return "{}:{}".format(int(number1 / divisor), int(number2 / divisor))
519
+
520
+
521
+ def transpose(matrix):
522
+ """Transpose the given matrix. See https://en.wikipedia.org/wiki/Transpose."""
523
+
524
+ if not matrix or not matrix[0]:
525
+ print("Empty matrix provided")
526
+ return None
527
+
528
+ transposed_matrix = [[matrix[j][i] for j in range(len(matrix))] for i in range(len(matrix[0]))]
529
+
530
+ return transposed_matrix
531
+
532
+
533
+ def number_line(value, min_, max_, interval: int = 1):
534
+ if min_ > max_:
535
+ raise RuntimeError('The minimum value "{}" is greater than the maximum value "{}"'.format(min_, max_))
536
+ if value > max_:
537
+ raise RuntimeError('The value "{}" is greater than the maximum value of "{}"'.format(value, max_))
538
+ if value < min_:
539
+ raise RuntimeError('The value "{}" is less than the minimum value of "{}"'.format(value, min_))
540
+
541
+ # find the length of the numberline between the value and the min_
542
+ length_below_value = int(((value - min_) / interval) - 1)
543
+ # find the length of the numberline between the max_ and the value
544
+ length_above_value = int(((max_ - value) / interval) - 1)
545
+
546
+ # create the numberline
547
+ if length_below_value < 0:
548
+ number_line_string = "({})|{}{}".format(min_, "." * length_above_value, max_)
549
+ elif length_above_value < 0:
550
+ number_line_string = "{}{}|({})".format(min_, "." * length_below_value, max_)
551
+ else:
552
+ number_line_string = "{}{}|{}{}".format(min_, "." * length_below_value, "." * length_above_value, max_)
553
+
554
+ return number_line_string
555
+
556
+
557
+ # start numbers_wrapper
558
+ # TODO: add a decorator to convert first arg to integer
559
+ def number_zero_pad(num: StrOrNumberType, length: StrOrNumberType) -> str:
560
+ """."""
561
+ num = int(num) # type: ignore[arg-type]
562
+ if length < len(str(num)): # type: ignore[operator]
563
+ message = "The length you provided is shorter than the number. Please provide a length that is at least as long as the given number." # noqa: E501
564
+ raise ValueError(message)
565
+
566
+ zero_padded_number = f"{num}"
567
+
568
+ while len(zero_padded_number) < length: # type: ignore[operator]
569
+ zero_padded_number = f"0{zero_padded_number}"
570
+
571
+ return zero_padded_number
572
+
573
+
574
+ def is_number(item):
575
+ """Return whether or not the item is a number."""
576
+ if isinstance(item, str):
577
+ try:
578
+ int(item)
579
+ except ValueError:
580
+ try:
581
+ float(item)
582
+ except ValueError:
583
+ return False
584
+ else:
585
+ return True
586
+ else:
587
+ return True
588
+ else:
589
+ return isinstance(item, numbers.Number)
590
+
591
+
592
+ @arguments_as_decimals
593
+ def number_is_even(number: StrOrNumberType):
594
+ remainder_two = remainder(number, 2)
595
+ is_even = remainder_two == 0
596
+ return is_even
597
+
598
+
599
+ @arguments_as_decimals
600
+ def number_is_odd(number: StrOrNumberType):
601
+ is_even = number_is_even(number)
602
+ return not is_even
603
+
604
+
605
+ def number_is_approx(number, approximate_value, *, relative_tolerance=1e-6):
606
+ """."""
607
+ is_close = math.isclose(number, approximate_value, rel_tol=relative_tolerance)
608
+ return is_close
609
+
610
+
611
+ # TODO: rename this function as `enumerate` is already a python function
612
+ def enumerate_range(range_string, range_split_string: str = "-"):
613
+ """Enumerate the range specified by the string. For example, `1-3` returns `[1, 2, 3]`."""
614
+ range_sections = range_string.split(range_split_string)
615
+ error_message = "The enumerate_range function expects a string with two integers separated by the character specified by the `range_split_string` argument which can be passed into the enumerate_range function." # noqa: E501
616
+
617
+ if len(range_sections) != 2:
618
+ raise ValueError(error_message)
619
+
620
+ try:
621
+ range_start = int(range_sections[0].strip())
622
+ range_end = int(range_sections[1].strip())
623
+ except ValueError:
624
+ raise ValueError(error_message)
625
+ else:
626
+ return [i for i in range(range_start, range_end + 1)]
627
+
628
+
629
+ def hex_endiness_swap(hex_string):
630
+ """Credit to: https://stackoverflow.com/questions/27506474/how-to-byte-swap-a-32-bit-integer-in-python."""
631
+ import struct
632
+
633
+ return "{:08x}".format(struct.unpack("<I", struct.pack(">I", hex_string))[0])
634
+
635
+
636
+ def number_to_words(number):
637
+ """Convert a number to its English representation (e.g. 100 => "One Hundred")."""
638
+ from d8s_strings.strings import _inflect_engine
639
+
640
+ return _inflect_engine().number_to_words(number)
641
+
642
+
643
+ @arguments_as_decimals
644
+ def number_to_scientific_notation(number):
645
+ """Convert the given number to scientific notation."""
646
+ precision = str(len(str(number)) + 1)
647
+ scientific_notation_number = f"{number:.{precision}E}"
648
+
649
+ # credits for the solution below to https://stackoverflow.com/a/6913576
650
+ return (
651
+ scientific_notation_number.split("E")[0].rstrip("0").rstrip(".")
652
+ + "E"
653
+ + scientific_notation_number.split("E")[1]
654
+ )
655
+
656
+
657
+ def number_to_engineering_notation(number):
658
+ """Convert the given number to engineering notation."""
659
+ import decimal
660
+
661
+ decimal_form = decimal.Decimal(number)
662
+ return decimal_form.normalize().to_eng_string()
663
+
664
+
665
+ def hex_get_bytes(hex_number, number_of_bytes):
666
+ length = len(hex(hex_number)) - 2
667
+ hex_num_bytes = length / 2
668
+
669
+ if (hex_num_bytes < number_of_bytes) or (hex_num_bytes == number_of_bytes):
670
+ return hex(hex_number)
671
+ else:
672
+ hex_number = hex_number >> math.floor((8 * (hex_num_bytes - number_of_bytes)))
673
+ final_hex = hex(hex_number)
674
+ return final_hex