1/*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Interval arithmetic.
22 *//*--------------------------------------------------------------------*/
23
24#include "tcuInterval.hpp"
25
26#include "deMath.h"
27
28#include <cmath>
29
30namespace tcu
31{
32
33using std::ldexp;
34
35Interval applyMonotone (DoubleFunc1& func, const Interval& arg0)
36{
37	Interval ret;
38	TCU_INTERVAL_APPLY_MONOTONE1(ret, x, arg0, val,
39								 TCU_SET_INTERVAL(val, point, point = func(x)));
40	return ret;
41}
42
43Interval applyMonotone (DoubleIntervalFunc1& func, const Interval& arg0)
44{
45	return Interval(func(arg0.lo()), func(arg0.hi()));
46}
47
48Interval applyMonotone (DoubleFunc2& func, const Interval& arg0, const Interval& arg1)
49{
50	Interval ret;
51
52	TCU_INTERVAL_APPLY_MONOTONE2(ret, x, arg0, y, arg1, val,
53								 TCU_SET_INTERVAL(val, point, point = func(x, y)));
54
55	return ret;
56}
57
58Interval applyMonotone (DoubleIntervalFunc2& func, const Interval& arg0, const Interval& arg1)
59{
60	double	lo0 = arg0.lo(), hi0 = arg0.hi(), lo1 = arg1.lo(), hi1 = arg1.hi();
61	return Interval(Interval(func(lo0, lo1), func(lo0, hi1)),
62					Interval(func(hi0, lo1), func(hi0, hi1)));
63}
64
65Interval operator+ (const Interval& x, const Interval& y)
66{
67	Interval ret;
68
69	if (!x.empty() && !y.empty())
70		TCU_SET_INTERVAL_BOUNDS(ret, p, p = x.lo() + y.lo(), p = x.hi() + y.hi());
71	if (x.hasNaN() || y.hasNaN())
72		ret |= TCU_NAN;
73
74	return ret;
75}
76
77Interval operator- (const Interval& x, const Interval& y)
78{
79	Interval ret;
80
81	TCU_INTERVAL_APPLY_MONOTONE2(ret, xp, x, yp, y, val,
82								 TCU_SET_INTERVAL(val, point, point = xp - yp));
83	return ret;
84}
85
86Interval operator* (const Interval& x, const Interval& y)
87{
88	Interval ret;
89
90	TCU_INTERVAL_APPLY_MONOTONE2(ret, xp, x, yp, y, val,
91								 TCU_SET_INTERVAL(val, point, point = xp * yp));
92	return ret;
93}
94
95Interval operator/ (const Interval& nom, const Interval& den)
96{
97	if (den.contains(0.0))
98	{
99		// \todo [2014-03-21 lauri] Non-inf endpoint when one den endpoint is
100		// zero and nom doesn't cross zero?
101		return Interval::unbounded();
102	}
103	else
104	{
105		Interval ret;
106
107		TCU_INTERVAL_APPLY_MONOTONE2(ret, nomp, nom, denp, den, val,
108									 TCU_SET_INTERVAL(val, point, point = nomp / denp));
109		return ret;
110	}
111}
112
113static double negate (double x)
114{
115	return -x;
116}
117
118Interval operator- (const Interval& x)
119{
120	return applyMonotone(negate, x);
121}
122
123Interval exp2 (const Interval& x)
124{
125	return applyMonotone(std::pow, 2.0, x);
126}
127
128Interval exp (const Interval& x)
129{
130	return applyMonotone(std::exp, x);
131}
132
133Interval sqrt (const Interval& x)
134{
135	return applyMonotone(std::sqrt, x);
136}
137
138Interval inverseSqrt (const Interval& x)
139{
140	return 1.0 / sqrt(x);
141}
142
143Interval abs (const Interval& x)
144{
145	const Interval mono = applyMonotone(std::abs, x);
146
147	if (x.contains(0.0))
148		return Interval(0.0, mono);
149
150	return mono;
151}
152
153std::ostream& operator<< (std::ostream& os, const Interval& interval)
154{
155	if (interval.empty())
156		if (interval.hasNaN())
157			os << "[NaN]";
158		else
159			os << "()";
160	else
161		os << (interval.hasNaN() ? "~" : "")
162		   << "[" << interval.lo() << ", " << interval.hi() << "]";
163	return os;
164}
165
166} // tcu
167