-
-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
streamlining Horner's rule functionality across Universal
- Loading branch information
1 parent
c0dd3fe
commit cf955af
Showing
16 changed files
with
257 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,18 @@ | ||
#pragma once | ||
// functions.hpp: aggregation of all Universal number library functions | ||
// | ||
// Copyright (C) 2017-2020 Stillwater Supercomputing, Inc. | ||
// Copyright (C) 2017 Stillwater Supercomputing, Inc. | ||
// SPDX-License-Identifier: MIT | ||
// | ||
// This file is part of the universal numbers project, which is released under an MIT Open Source license. | ||
|
||
// properties of a number | ||
#include "isrepresentable.hpp" | ||
#include "twosum.hpp" | ||
#include <universal/functions/isrepresentable.hpp> | ||
|
||
// special functions | ||
#include "factorial.hpp" | ||
#include "binomial.hpp" | ||
#include "loss.hpp" | ||
#include <universal/functions/factorial.hpp> | ||
#include <universal/functions/binomial.hpp> | ||
#include <universal/functions/loss.hpp> | ||
|
||
// generic mathematical functions | ||
#include <universal/functions/horners.hpp> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#pragma once | ||
// horners.hpp: generic Horner's polynomial evaluation and root finding functions | ||
// | ||
// Copyright (C) 2017 Stillwater Supercomputing, Inc. | ||
// SPDX-License-Identifier: MIT | ||
// | ||
// This file is part of the universal numbers project, which is released under an MIT Open Source license. | ||
|
||
namespace sw { namespace universal { | ||
|
||
/// <summary> | ||
/// polyeval evaluates a given n-th degree polynomial at x using Horner's rule. | ||
/// The polynomial is given by the array of (n+1) coefficients. | ||
/// </summary> | ||
/// <param name="c">polynomial coefficients</param> | ||
/// <param name="n">portion of the polynomial to evaluate</param> | ||
/// <param name="x">value to evaluate</param> | ||
/// <returns>polynomial at x</returns> | ||
template<typename Vector, typename Scalar> | ||
inline Scalar polyeval(const Vector& coefficients, int n, const Scalar& x) { | ||
// Horner's method of polynomial evaluation | ||
assert(coefficients.size() > n); | ||
Scalar r{ coefficients[n] }; | ||
|
||
for (int i = n - 1; i >= 0; --i) { | ||
r *= x; | ||
r += coefficients[i]; | ||
} | ||
|
||
return r; | ||
} | ||
|
||
/// <summary> | ||
/// polyroot finds a root close to the initial guess x0. | ||
/// Will only find a single root as it is using a Newton iteration | ||
/// </summary> | ||
/// <param name="c">n-th degree polynomial</param> | ||
/// <param name="x0">initial guess of the root of interest</param> | ||
/// <param name="max_iter">stopping criterium</param> | ||
/// <param name="threshold">stopping cirterium</param> | ||
/// <returns>root closest to initial guess x0</returns> | ||
template<typename Vector, typename Scalar> | ||
inline Scalar polyroot(const Vector& c, const Scalar& x0, int max_iter, double threshold = 1e-16) { | ||
if (threshold == 0.0) threshold = std::numeric_limits<Scalar>::epsilon(); | ||
|
||
int n = c.size() - 1; | ||
double max_c = std::abs(double(c[0])); | ||
// Compute the coefficients of the derivatives | ||
Vector derivatives{ c }; | ||
for (int i = 1; i <= n; ++i) { | ||
double v = std::abs(double(c[i])); | ||
if (v > max_c) max_c = v; | ||
derivatives[i - 1] = c[i] * static_cast<double>(i); | ||
} | ||
threshold *= max_c; | ||
|
||
// Newton iteration | ||
bool converged{ false }; | ||
Scalar x = x0; | ||
for (int i = 0; i < max_iter; ++i) { | ||
Scalar f = polyeval(c, n, x); | ||
|
||
if (abs(f) < threshold) { | ||
converged = true; | ||
break; | ||
} | ||
x -= (f / polyeval(derivatives, n - 1, x)); | ||
} | ||
|
||
if (!converged) { | ||
std::cerr << "polyroot: failed to converge\n"; | ||
return Scalar(SpecificValue::snan); | ||
} | ||
|
||
return x; | ||
} | ||
|
||
}} // namespace sw::universal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#pragma once | ||
// mathext.hpp: definition of mathematical extension functions for the classic floats | ||
// | ||
// Copyright (C) 2017 Stillwater Supercomputing, Inc. | ||
// SPDX-License-Identifier: MIT | ||
// | ||
// This file is part of the universal numbers project, which is released under an MIT Open Source license. | ||
|
||
#include <universal/number/cfloat/mathext/horners.hpp> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#pragma once | ||
// horners.hpp: Horner's polynomial evaluation and root finding functions for double-double (dd) floating-point | ||
// | ||
// Copyright (C) 2017 Stillwater Supercomputing, Inc. | ||
// SPDX-License-Identifier: MIT | ||
// | ||
// This file is part of the universal numbers project, which is released under an MIT Open Source license. | ||
#include <vector> | ||
#include <universal/number/cfloat/cfloat_fwd.hpp> | ||
|
||
namespace sw { namespace universal { | ||
|
||
/// <summary> | ||
/// polyeval evaluates a given n-th degree polynomial at x using Horner's rule. | ||
/// The polynomial is given by the array of (n+1) coefficients. | ||
/// </summary> | ||
/// <param name="c">polynomial coefficients</param> | ||
/// <param name="n">portion of the polynomial to evaluate</param> | ||
/// <param name="x">value to evaluate</param> | ||
/// <returns>polynomial at x</returns> | ||
template<unsigned nbits, unsigned es, typename BlockType, bool hasSubnormals, bool hasSupernormals, bool isSaturating> | ||
inline cfloat<nbits, es, BlockType, hasSubnormals, hasSupernormals, isSaturating> polyeval(const std::vector<cfloat<nbits, es, BlockType, hasSubnormals, hasSupernormals, isSaturating>>& coefficients, int n, const cfloat<nbits, es, BlockType, hasSubnormals, hasSupernormals, isSaturating>& x) { | ||
// Horner's method of polynomial evaluation | ||
assert(coefficients.size() > n); | ||
cfloat<nbits, es, BlockType, hasSubnormals, hasSupernormals, isSaturating> r = coefficients[n]; | ||
|
||
for (int i = n - 1; i >= 0; --i) { | ||
r *= x; | ||
r += coefficients[i]; | ||
} | ||
|
||
return r; | ||
} | ||
|
||
/* polyroot(c, n, x0) | ||
Given an n-th degree polynomial, finds a root close to | ||
the given guess x0. Note that this uses simple Newton | ||
iteration scheme, and does not work for multiple roots. */ | ||
|
||
template<unsigned nbits, unsigned es, typename BlockType, bool hasSubnormals, bool hasSupernormals, bool isSaturating> | ||
inline cfloat<nbits, es, BlockType, hasSubnormals, hasSupernormals, isSaturating> polyroot(const std::vector<cfloat<nbits, es, BlockType, hasSubnormals, hasSupernormals, isSaturating>>& c, const cfloat<nbits, es, BlockType, hasSubnormals, hasSupernormals, isSaturating>& x0, int n, int max_iter, double threshold) { | ||
using Cfloat = cfloat<nbits, es, BlockType, hasSubnormals, hasSupernormals, isSaturating>; | ||
if (threshold == 0.0) threshold = std::numeric_limits<Cfloat>::epsilon(); | ||
|
||
int n = c.size() - 1; | ||
double max_c = std::abs(double(c[0])); | ||
// Compute the coefficients of the derivatives | ||
std::vector<Cfloat> derivatives{ c }; | ||
for (int i = 1; i <= n; i++) { | ||
double v = std::abs(double(c[i])); | ||
if (v > max_c) max_c = v; | ||
derivatives[i - 1] = c[i] * static_cast<double>(i); | ||
} | ||
threshold *= max_c; | ||
|
||
// Newton iteration | ||
bool converged{ false }; | ||
Cfloat x = x0; | ||
for (int i = 0; i < max_iter; i++) { | ||
Cfloat f = polyeval(c, n, x); | ||
|
||
if (abs(f) < threshold) { | ||
converged = true; | ||
break; | ||
} | ||
x -= (f / polyeval(derivatives, n - 1, x)); | ||
} | ||
|
||
if (!converged) { | ||
std::cerr << "polyroot: failed to converge\n"; | ||
return Cfloat(SpecificValue::snan); | ||
} | ||
|
||
return x; | ||
} | ||
|
||
}} // namespace sw::universal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.