diff --git a/README.md b/README.md
index eb43775..f9abb38 100644
--- a/README.md
+++ b/README.md
@@ -514,6 +514,8 @@ Licensed under either of Apache License, Version
href="LICENSE-BOOST">BOOST license.
+
+
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this repository by you, as defined in the Apache-2.0 license,
diff --git a/script/amalgamate.py b/script/amalgamate.py
index 3565922..78e9961 100644
--- a/script/amalgamate.py
+++ b/script/amalgamate.py
@@ -1,100 +1,122 @@
# text parts
-processed_files = { }
+processed_files = {}
# authors
-for filename in ['AUTHORS', 'CONTRIBUTORS']:
- with open(filename, encoding='utf8') as f:
- text = ''
- for line in f:
- if filename == 'AUTHORS':
- text += '// fast_float by ' + line
- if filename == 'CONTRIBUTORS':
- text += '// with contributions from ' + line
- processed_files[filename] = text + '//\n//\n'
+for filename in ["AUTHORS", "CONTRIBUTORS"]:
+ with open(filename, encoding="utf8") as f:
+ text = ""
+ for line in f:
+ if filename == "AUTHORS":
+ text += "// fast_float by " + line
+ if filename == "CONTRIBUTORS":
+ text += "// with contributions from " + line
+ processed_files[filename] = text + "//\n//\n"
# licenses
-for filename in ['LICENSE-MIT', 'LICENSE-APACHE', 'LICENSE-BOOST']:
- lines = []
- with open(filename, encoding='utf8') as f:
- lines = f.readlines()
+for filename in ["LICENSE-MIT", "LICENSE-APACHE", "LICENSE-BOOST"]:
+ lines = []
+ with open(filename, encoding="utf8") as f:
+ lines = f.readlines()
- # Retrieve subset required for inclusion in source
- if filename == 'LICENSE-APACHE':
- lines = [
- ' Copyright 2021 The fast_float authors\n',
- *lines[179:-1]
- ]
+ # Retrieve subset required for inclusion in source
+ if filename == "LICENSE-APACHE":
+ lines = [" Copyright 2021 The fast_float authors\n", *lines[179:-1]]
- text = ''
- for line in lines:
- line = line.strip()
- if len(line):
- line = ' ' + line
- text += '//' + line + '\n'
- processed_files[filename] = text
+ text = ""
+ for line in lines:
+ line = line.strip()
+ if len(line):
+ line = " " + line
+ text += "//" + line + "\n"
+ processed_files[filename] = text
# code
-for filename in [ 'constexpr_feature_detect.h', 'float_common.h', 'fast_float.h', 'ascii_number.h',
- 'fast_table.h', 'decimal_to_binary.h', 'bigint.h', 'digit_comparison.h', 'parse_number.h']:
- with open('include/fast_float/' + filename, encoding='utf8') as f:
- text = ''
- for line in f:
- if line.startswith('#include "'): continue
- text += line
- processed_files[filename] = '\n' + text
+for filename in [
+ "constexpr_feature_detect.h",
+ "float_common.h",
+ "fast_float.h",
+ "ascii_number.h",
+ "fast_table.h",
+ "decimal_to_binary.h",
+ "bigint.h",
+ "digit_comparison.h",
+ "parse_number.h",
+]:
+ with open("include/fast_float/" + filename, encoding="utf8") as f:
+ text = ""
+ for line in f:
+ if line.startswith('#include "'):
+ continue
+ text += line
+ processed_files[filename] = "\n" + text
# command line
import argparse
-parser = argparse.ArgumentParser(description='Amalgamate fast_float.')
-parser.add_argument('--license', default='TRIPLE', choices=['DUAL', 'TRIPLE', 'MIT', 'APACHE', 'BOOST'], help='choose license')
-parser.add_argument('--output', default='', help='output file (stdout if none')
+parser = argparse.ArgumentParser(description="Amalgamate fast_float.")
+parser.add_argument(
+ "--license",
+ default="TRIPLE",
+ choices=["DUAL", "TRIPLE", "MIT", "APACHE", "BOOST"],
+ help="choose license",
+)
+parser.add_argument("--output", default="", help="output file (stdout if none")
args = parser.parse_args()
+
def license_content(license_arg):
- result = []
- if license_arg == 'TRIPLE':
- result += [
- '// Licensed under the Apache License, Version 2.0, or the\n',
- '// MIT License or the Boost License. This file may not be copied,\n',
- '// modified, or distributed except according to those terms.\n',
- '//\n'
- ]
- if license_arg == 'DUAL':
- result += [
- '// Licensed under the Apache License, Version 2.0, or the\n',
- '// MIT License at your option. This file may not be copied,\n',
- '// modified, or distributed except according to those terms.\n',
- '//\n'
- ]
+ result = []
+ if license_arg == "TRIPLE":
+ result += [
+ "// Licensed under the Apache License, Version 2.0, or the\n",
+ "// MIT License or the Boost License. This file may not be copied,\n",
+ "// modified, or distributed except according to those terms.\n",
+ "//\n",
+ ]
+ if license_arg == "DUAL":
+ result += [
+ "// Licensed under the Apache License, Version 2.0, or the\n",
+ "// MIT License at your option. This file may not be copied,\n",
+ "// modified, or distributed except according to those terms.\n",
+ "//\n",
+ ]
+
+ if license_arg in ("DUAL", "TRIPLE", "MIT"):
+ result.append("// MIT License Notice\n//\n")
+ result.append(processed_files["LICENSE-MIT"])
+ result.append("//\n")
+ if license_arg in ("DUAL", "TRIPLE", "APACHE"):
+ result.append("// Apache License (Version 2.0) Notice\n//\n")
+ result.append(processed_files["LICENSE-APACHE"])
+ result.append("//\n")
+ if license_arg in ("TRIPLE", "BOOST"):
+ result.append("// BOOST License Notice\n//\n")
+ result.append(processed_files["LICENSE-BOOST"])
+ result.append("//\n")
- if license_arg in ('DUAL', 'TRIPLE', 'MIT'):
- result.append('// MIT License Notice\n//\n')
- result.append(processed_files['LICENSE-MIT'])
- result.append('//\n')
- if license_arg in ('DUAL', 'TRIPLE', 'APACHE'):
- result.append('// Apache License (Version 2.0) Notice\n//\n')
- result.append(processed_files['LICENSE-APACHE'])
- result.append('//\n')
- if license_arg in ('TRIPLE', 'BOOST'):
- result.append('// BOOST License Notice\n//\n')
- result.append(processed_files['LICENSE-BOOST'])
- result.append('//\n')
+ return result
- return result
-text = ''.join([
- processed_files['AUTHORS'], processed_files['CONTRIBUTORS'],
- *license_content(args.license),
- processed_files['constexpr_feature_detect.h'],
- processed_files['float_common.h'], processed_files['fast_float.h'],
- processed_files['ascii_number.h'], processed_files['fast_table.h'],
- processed_files['decimal_to_binary.h'], processed_files['bigint.h'],
- processed_files['digit_comparison.h'], processed_files['parse_number.h']])
+text = "".join(
+ [
+ processed_files["AUTHORS"],
+ processed_files["CONTRIBUTORS"],
+ *license_content(args.license),
+ processed_files["constexpr_feature_detect.h"],
+ processed_files["float_common.h"],
+ processed_files["fast_float.h"],
+ processed_files["ascii_number.h"],
+ processed_files["fast_table.h"],
+ processed_files["decimal_to_binary.h"],
+ processed_files["bigint.h"],
+ processed_files["digit_comparison.h"],
+ processed_files["parse_number.h"],
+ ]
+)
if args.output:
- with open(args.output, 'wt', encoding='utf8') as f:
- f.write(text)
+ with open(args.output, "wt", encoding="utf8") as f:
+ f.write(text)
else:
- print(text)
+ print(text)
diff --git a/script/analysis.py b/script/analysis.py
index 8dcbcd5..08f5c49 100644
--- a/script/analysis.py
+++ b/script/analysis.py
@@ -1,36 +1,38 @@
+import sys
from math import floor
+
def log2(x):
- """returns ceil(log2(x)))"""
- y = 0
- while((1<= 2**127
- K = 2**127
- if(not(c * K * d<=( K + 1) * t)):
- print(q)
- top = floor(t/(c * d - t))
- sys.exit(-1)
+ t = 2 ** b
+ c = t // d + 1
+ assert c < 2 ** 128
+ assert c >= 2 ** 127
+ K = 2 ** 127
+ if not (c * K * d <= (K + 1) * t):
+ print(q)
+ top = floor(t / (c * d - t))
+ sys.exit(-1)
-for q in range(18, 344+1):
- d = 5**q
- b = 64 + 2*log2(d)
- t = 2**b
- c = t//d + 1
- assert c > 2**(64 +log2(d))
- K = 2**64
- if(not(c * K * d<=( K + 1) * t)):
- print(q)
- top = floor(t/(c * d - t))
- sys.exit(-1)
+for q in range(18, 344 + 1):
+ d = 5 ** q
+ b = 64 + 2 * log2(d)
+ t = 2 ** b
+ c = t // d + 1
+ assert c > 2 ** (64 + log2(d))
+ K = 2 ** 64
+ if not (c * K * d <= (K + 1) * t):
+ print(q)
+ top = floor(t / (c * d - t))
+ sys.exit(-1)
-print("all good")
\ No newline at end of file
+print("all good")
diff --git a/script/mushtak_lemire.py b/script/mushtak_lemire.py
index 5b98fda..46c8c64 100644
--- a/script/mushtak_lemire.py
+++ b/script/mushtak_lemire.py
@@ -9,25 +9,25 @@
# Appendix B of Number parsing at a gigabyte per second.
# Software: Practice and Experience 2021;51(8):1700–1727.
for q in range(-342, -27):
- power5 = 5**-q
+ power5 = 5 ** -q
z = 0
while (1 << z) < power5:
z += 1
b = 2 * z + 2 * 64
- c = 2**b // power5 + 1
+ c = 2 ** b // power5 + 1
while c >= (1 << 128):
c //= 2
all_tqs.append(c)
for q in range(-27, 0):
- power5 = 5**-q
+ power5 = 5 ** -q
z = 0
while (1 << z) < power5:
z += 1
b = z + 127
- c = 2**b // power5 + 1
+ c = 2 ** b // power5 + 1
all_tqs.append(c)
for q in range(0, 308 + 1):
- power5 = 5**q
+ power5 = 5 ** q
while power5 < (1 << 127):
power5 *= 2
while power5 >= (1 << 128):
@@ -44,6 +44,7 @@ def continued_fraction(numer, denom):
numer, denom = denom, rem
return cf
+
# Given a continued fraction [a0; a1, a2, ..., an], returns
# all the convergents of that continued fraction
# as pairs of the form (numer, denom), where numer/denom is
@@ -58,17 +59,22 @@ def convergents(cf):
p_n = a_n * p_n_minus_1 + p_n_minus_2
q_n = a_n * q_n_minus_1 + q_n_minus_2
convergents.append((p_n, q_n))
- p_n_minus_2, q_n_minus_2, p_n_minus_1, q_n_minus_1 = p_n_minus_1, q_n_minus_1, p_n, q_n
+ p_n_minus_2, q_n_minus_2, p_n_minus_1, q_n_minus_1 = (
+ p_n_minus_1,
+ q_n_minus_1,
+ p_n,
+ q_n,
+ )
return convergents
# Enumerate through all the convergents of T[q] / 2^137 with denominators < 2^64
found_solution = False
for j, tq in enumerate(all_tqs):
- for _, w in convergents(continued_fraction(tq, 2**137)):
- if w >= 2**64:
+ for _, w in convergents(continued_fraction(tq, 2 ** 137)):
+ if w >= 2 ** 64:
break
- if (tq*w) % 2**137 > 2**137 - 2**64:
+ if (tq * w) % 2 ** 137 > 2 ** 137 - 2 ** 64:
print(f"SOLUTION: q={j-342} T[q]={tq} w={w}")
found_solution = True
if not found_solution:
diff --git a/script/release.py b/script/release.py
index 064a10e..4bcf6c8 100755
--- a/script/release.py
+++ b/script/release.py
@@ -8,129 +8,176 @@
import io
import os
import fileinput
+
if sys.version_info < (3, 0):
sys.stdout.write("Sorry, requires Python 3.x or better\n")
sys.exit(1)
+
def colored(r, g, b, text):
- return "\033[38;2;{};{};{}m{} \033[38;2;255;255;255m".format(r, g, b, text)
+ return f"\033[38;2;{r};{g};{b}m{text} \033[38;2;255;255;255m"
+
def extractnumbers(s):
- return tuple(map(int,re.findall(r"(\d+)\.(\d+)\.(\d+)",str(s))[0]))
+ return tuple(map(int, re.findall(r"(\d+)\.(\d+)\.(\d+)", str(s))[0]))
+
def toversionstring(major, minor, rev):
- return str(major)+"."+str(minor)+"."+str(rev)
+ return f"{major}.{minor}.{rev}"
+
-def topaddedversionstring(major, minor, rev):
- return str(major)+str(minor).zfill(3)+str(rev).zfill(3)
print("Calling git rev-parse --abbrev-ref HEAD")
-pipe = subprocess.Popen(["git", "rev-parse", "--abbrev-ref", "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+pipe = subprocess.Popen(
+ ["git", "rev-parse", "--abbrev-ref", "HEAD"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+)
branchresult = pipe.communicate()[0].decode().strip()
-if(branchresult != "main"):
- print(colored(255, 0, 0, "We recommend that you release on main, you are on '"+branchresult+"'"))
+if branchresult != "main":
+ print(
+ colored(
+ 255,
+ 0,
+ 0,
+ f"We recommend that you release on main, you are on '{branchresult}'",
+ )
+ )
ret = subprocess.call(["git", "remote", "update"])
-if(ret != 0):
+if ret != 0:
sys.exit(ret)
print("Calling git log HEAD.. --oneline")
-pipe = subprocess.Popen(["git", "log", "HEAD..", "--oneline"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+pipe = subprocess.Popen(
+ ["git", "log", "HEAD..", "--oneline"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+)
uptodateresult = pipe.communicate()[0].decode().strip()
-if(len(uptodateresult) != 0):
+if len(uptodateresult) != 0:
print(uptodateresult)
sys.exit(-1)
-pipe = subprocess.Popen(["git", "rev-parse", "--show-toplevel"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+pipe = subprocess.Popen(
+ ["git", "rev-parse", "--show-toplevel"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+)
maindir = pipe.communicate()[0].decode().strip()
scriptlocation = os.path.dirname(os.path.abspath(__file__))
-print("repository: "+maindir)
+print(f"repository: {maindir}")
-pipe = subprocess.Popen(["git", "describe", "--abbrev=0", "--tags"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+pipe = subprocess.Popen(
+ ["git", "describe", "--abbrev=0", "--tags"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+)
versionresult = pipe.communicate()[0].decode().strip()
-print("last version: "+versionresult )
+print(f"last version: {versionresult}")
try:
- currentv = extractnumbers(versionresult)
+ currentv = extractnumbers(versionresult)
except:
- currentv = [0,0,0]
-if(len(sys.argv) != 2):
- nextv = (currentv[0],currentv[1], currentv[2]+1)
- print ("please specify version number, e.g. "+toversionstring(*nextv))
+ currentv = [0, 0, 0]
+if len(sys.argv) != 2:
+ nextv = (currentv[0], currentv[1], currentv[2] + 1)
+ print(f"please specify version number, e.g. {toversionstring(*nextv)}")
sys.exit(-1)
try:
newversion = extractnumbers(sys.argv[1])
print(newversion)
except:
- print("can't parse version number "+sys.argv[1])
+ print(f"can't parse version number {sys.argv[1]}")
sys.exit(-1)
print("checking that new version is valid")
-if(newversion[0] != currentv[0]):
- assert newversion[0] == currentv[0] + 1
+if newversion[0] != currentv[0]:
+ assert newversion[0] == currentv[0] + 1
assert newversion[1] == 0
assert newversion[2] == 0
-elif (newversion[1] != currentv[1]):
- assert newversion[1] == currentv[1] + 1
+elif newversion[1] != currentv[1]:
+ assert newversion[1] == currentv[1] + 1
assert newversion[2] == 0
-else :
- assert newversion[2] == currentv[2] + 1
-
-atleastminor= (currentv[0] != newversion[0]) or (currentv[1] != newversion[1])
-
+else:
+ assert newversion[2] == currentv[2] + 1
+atleastminor = (currentv[0] != newversion[0]) or (currentv[1] != newversion[1])
newmajorversionstring = str(newversion[0])
-mewminorversionstring = str(newversion[1])
-newrevversionstring = str(newversion[2])
-newversionstring = str(newversion[0]) + "." + str(newversion[1]) + "." + str(newversion[2])
-cmakefile = maindir + os.sep + "CMakeLists.txt"
-
-
-for line in fileinput.input(cmakefile, inplace=1, backup='.bak'):
- line = re.sub(r'project\(fast_float VERSION \d+\.\d+\.\d+ LANGUAGES CXX\)','project(fast_float VERSION '+newmajorversionstring+'.'+mewminorversionstring+'.'+newrevversionstring+" LANGUAGES CXX)", line.rstrip())
+newminorversionstring = str(newversion[1])
+newpatchversionstring = str(newversion[2])
+newversionstring = f"{newversion[0]}.{newversion[1]}.{newversion[2]}"
+cmakefile = f"{maindir}{os.sep}CMakeLists.txt"
+
+for line in fileinput.input(cmakefile, inplace=1, backup=".bak"):
+ line = re.sub(
+ r"project\(fast_float VERSION \d+\.\d+\.\d+ LANGUAGES CXX\)",
+ f"project(fast_float VERSION {newversionstring} LANGUAGES CXX)",
+ line.rstrip(),
+ )
print(line)
-print("modified "+cmakefile+", a backup was made")
-
-
-
-versionfilerel = os.sep + "include" + os.sep + "fast_float" + os.sep + "float_common.h"
-versionfile = maindir + versionfilerel
-
-for line in fileinput.input(versionfile, inplace=1, backup='.bak'):
- line = re.sub(r'#define FASTFLOAT_VERSION_MAJOR \d+','#define FASTFLOAT_VERSION_MAJOR '+newmajorversionstring, line.rstrip())
- line = re.sub(r'#define FASTFLOAT_VERSION_MINOR \d+','#define FASTFLOAT_VERSION_MAJOR '+mewminorversionstring, line.rstrip())
- line = re.sub(r'#define FASTFLOAT_VERSION_PATCH \d+','#define FASTFLOAT_VERSION_MAJOR '+newrevversionstring, line.rstrip())
+print(f"modified {cmakefile}, a backup was made")
+
+versionfilerel = f"{os.sep}include{os.sep}fast_float{os.sep}float_common.h"
+versionfile = f"{maindir}{versionfilerel}"
+
+for line in fileinput.input(versionfile, inplace=1, backup=".bak"):
+ line = re.sub(
+ r"#define FASTFLOAT_VERSION_MAJOR \d+",
+ f"#define FASTFLOAT_VERSION_MAJOR {newmajorversionstring}",
+ line.rstrip(),
+ )
+ line = re.sub(
+ r"#define FASTFLOAT_VERSION_MINOR \d+",
+ f"#define FASTFLOAT_VERSION_MINOR {newminorversionstring}",
+ line.rstrip(),
+ )
+ line = re.sub(
+ r"#define FASTFLOAT_VERSION_PATCH \d+",
+ f"#define FASTFLOAT_VERSION_PATCH {newpatchversionstring}",
+ line.rstrip(),
+ )
print(line)
-print(versionfile + " modified")
-
-
-readmefile = maindir + os.sep + "README.md"
-
-
-for line in fileinput.input(readmefile, inplace=1, backup='.bak'):
- line = re.sub(r'https://github.com/fastfloat/fast_float/releases/download/v(\d+\.\d+\.\d+)/fast_float.h','https://github.com/fastfloat/fast_float/releases/download/v'+newmajorversionstring+'.'+mewminorversionstring+'.'+newrevversionstring+'/fast_float.h', line.rstrip())
+print(f"{versionfile} modified")
+
+readmefile = f"{maindir}{os.sep}README.md"
+
+for line in fileinput.input(readmefile, inplace=1, backup=".bak"):
+ line = re.sub(
+ r"https://github.com/fastfloat/fast_float/releases/download/v(\d+\.\d+\.\d+)/fast_float.h",
+ f"https://github.com/fastfloat/fast_float/releases/download/v{newversionstring}/fast_float.h",
+ line.rstrip(),
+ )
+ line = re.sub(
+ r"GIT_TAG tags/v(\d+\.\d+\.\d+)",
+ f"GIT_TAG tags/v{newversionstring}",
+ line.rstrip(),
+ )
+ line = re.sub(
+ r"GIT_TAG v(\d+\.\d+\.\d+)\)", f"GIT_TAG v{newversionstring})", line.rstrip()
+ )
print(line)
-print("modified "+readmefile+", a backup was made")
-
+print(f"modified {readmefile}, a backup was made")
print("running amalgamate.py")
-with open(maindir+ os.sep + 'fast_float.h', "w") as outfile:
- cp = subprocess.run(["python3", maindir+ os.sep + "script/amalgamate.py"], stdout=outfile)
+with open(f"{maindir}{os.sep}fast_float.h", "w") as outfile:
+ cp = subprocess.run(
+ [f"python3", f"{maindir}{os.sep}script{os.sep}amalgamate.py"], stdout=outfile
+ )
-if(cp.returncode != 0):
+if cp.returncode != 0:
print("Failed to run amalgamate")
else:
print("amalgamate.py ran successfully")
- print("You should upload "+ maindir+ os.sep + 'fast_float.h')
-
-print("Please run the tests before issuing a release. \n")
-print("to issue release, enter \n git commit -a && git push && git tag -a v"+toversionstring(*newversion)+" -m \"version "+toversionstring(*newversion)+"\" && git push --tags \n")
-
-
+ print(f"You should upload {maindir}{os.sep}fast_float.h")
+print("Please run the tests before issuing a release.\n")
+print(
+ f'to issue release, enter\n git commit -a && git push && git tag -a v{toversionstring(*newversion)} -m "version {toversionstring(*newversion)}" && git push --tags\n'
+)
diff --git a/script/table_generation.py b/script/table_generation.py
index 24fec7c..223240f 100644
--- a/script/table_generation.py
+++ b/script/table_generation.py
@@ -1,14 +1,15 @@
def format(number):
- upper = number // (1<<64)
- lower = number % (1<<64)
- print(""+hex(upper)+","+hex(lower)+",")
+ upper = number // (1 << 64)
+ lower = number % (1 << 64)
+ print("" + hex(upper) + "," + hex(lower) + ",")
-for q in range(-342,0):
+
+for q in range(-342, 0):
power5 = 5 ** -q
z = 0
- while( (1<= -27):
+ if q >= -27:
b = z + 127
c = 2 ** b // power5 + 1
format(c)
@@ -16,16 +17,16 @@ def format(number):
b = 2 * z + 2 * 64
c = 2 ** b // power5 + 1
# truncate
- while(c >= (1<<128)):
- c //= 2
+ while c >= (1 << 128):
+ c //= 2
format(c)
-for q in range(0,308+1):
+for q in range(0, 308 + 1):
power5 = 5 ** q
# move the most significant bit in position
- while(power5 < (1<<127)):
+ while power5 < (1 << 127):
power5 *= 2
# *truncate*
- while(power5 >= (1<<128)):
+ while power5 >= (1 << 128):
power5 //= 2
format(power5)