Skip to content

Incorrect results of complex tan, complex tanh functions. #262

Closed
@cosurgi

Description

@cosurgi

Hi @jzmaddock , I followed your advice to use float_distance when measuring ULP error. I have implemented this check. For nearly all functions it was enough to set tolerance of 8 ULP with two notable excepions: real part of tan and imag part of tanh functions. See the pipeline warnings (scroll up the output to around line 360):

Here is a short snippet to reproduce these errors:

#include <boost/core/demangle.hpp>
#include <boost/math/complex.hpp>
#include <boost/math/special_functions.hpp>
#include <boost/multiprecision/float128.hpp>
#include <boost/multiprecision/mpfr.hpp>
#include <iostream>

template <typename T, typename Ref> void test()
{
	bool first = true;
	for (T x = -10.; x < 10.; x += 0.25)
		for (T y = -10.; y < 10.; y += 0.25) {
			std::complex<T>   z(x, y);
			std::complex<Ref> r(static_cast<Ref>(x), static_cast<Ref>(y));
			using boost::multiprecision::tan;
			using boost::multiprecision::tanh;
			auto z_tan  = tan(z).real();
			auto r_tan  = tan(r).real();
			auto z_tanh = tanh(z).imag();
			auto r_tanh = tanh(r).imag();
			if (first) {
				std::cout << boost::core::demangle(typeid(decltype(z_tan)).name()) << "\n";
				std::cout << boost::core::demangle(typeid(decltype(r_tan)).name()) << "\n";
				first = false;
			}
			auto dist_tan  = boost::math::float_distance(static_cast<T>(r_tan), z_tan);
			auto dist_tanh = boost::math::float_distance(static_cast<T>(r_tanh), z_tanh);
			if (dist_tan > 290000000)
				std::cout << "tan  error, args=" << z << " ULP dist=" << dist_tan << "\n";
			if (dist_tanh > 290000000)
				std::cout << "tanh error, args=" << z << " ULP dist=" << dist_tanh << "\n";
		}
	std::cout << "\n";
}

int main()
{
	test<boost::multiprecision::float128, boost::multiprecision::mpfr_float_50>();
	test<boost::multiprecision::mpfr_float_50, boost::multiprecision::mpfr_float_100>();
	test<boost::multiprecision::mpfr_float_100, boost::multiprecision::mpfr_float_500>();
}

Here I print only ULP errors larger than 290000000, otherwise it's a real flood. And all other functions pass with ULP error < 8 (except for cpp_bin_float - there I've set the limit to 200 with some exceptions for tgamma and lgamma).

Looks like I have stumbled upon a pretty large bug :).

This sample program produces following output:

boost::multiprecision::number<boost::multiprecision::backends::float128_backend, (boost::multiprecision::expression_template_option)0>
boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<50u, (boost::multiprecision::mpfr_allocation_type)1>, (boost::multiprecision::expression_template_option)1>
tanh error, args=(-10,-2.75) ULP dist=3.21107e+08
tanh error, args=(-10,3.25) ULP dist=3.36694e+08
tanh error, args=(-10,6.5) ULP dist=3.85652e+08
tanh error, args=(-9.75,-0.25) ULP dist=3.41471e+08
tan  error, args=(-2.75,-10) ULP dist=3.21107e+08
tan  error, args=(-0.25,-9.75) ULP dist=3.41471e+08
tan  error, args=(-0.25,9.75) ULP dist=3.41471e+08
tan  error, args=(3.25,-10) ULP dist=3.36694e+08
tan  error, args=(6.5,-10) ULP dist=3.85652e+08
tanh error, args=(9.75,-0.25) ULP dist=3.41471e+08

boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<50u, (boost::multiprecision::mpfr_allocation_type)1>, (boost::multiprecision::expression_template_option)1>
boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<100u, (boost::multiprecision::mpfr_allocation_type)1>, (boost::multiprecision::expression_template_option)1>
tanh error, args=(-10,-7.75) ULP dist=2.90069e+08
tan  error, args=(-7.75,-10) ULP dist=2.90069e+08

boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<100u, (boost::multiprecision::mpfr_allocation_type)1>, (boost::multiprecision::expression_template_option)1>
boost::multiprecision::number<boost::multiprecision::backends::mpfr_float_backend<500u, (boost::multiprecision::mpfr_allocation_type)1>, (boost::multiprecision::expression_template_option)1>
tanh error, args=(-9.75,-6.25) ULP dist=4.31581e+08
tanh error, args=(-9.75,-5.75) ULP dist=3.09252e+08
tanh error, args=(-9.75,4) ULP dist=3.86202e+08
tan  error, args=(-6.25,-9.75) ULP dist=4.31581e+08
tan  error, args=(-6.25,9.75) ULP dist=4.31581e+08
tan  error, args=(-5.75,-9.75) ULP dist=3.09252e+08
tan  error, args=(-5.75,9.75) ULP dist=3.09252e+08
tan  error, args=(4,-9.75) ULP dist=3.86202e+08
tan  error, args=(4,9.75) ULP dist=3.86202e+08
tanh error, args=(9.75,-6.25) ULP dist=4.31581e+08
tanh error, args=(9.75,-5.75) ULP dist=3.09252e+08
tanh error, args=(9.75,4) ULP dist=3.86202e+08

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions