

/***************************************************************************
 *
 * 26.c.math.cpp - test exercising [lib.c.math]
 *
 * $Id: 26.c.math.cpp 320933 2005-10-13 21:48:39Z sebor $
 *
 ***************************************************************************
 *
 * Copyright (c) 1994-2005 Quovadx,  Inc., acting through its  Rogue Wave
 * Software division. Licensed under the Apache License, Version 2.0 (the
 * "License");  you may  not use this file except  in compliance with the
 * License.    You    may   obtain   a   copy   of    the   License    at
 * http://www.apache.org/licenses/LICENSE-2.0.    Unless   required    by
 * applicable law  or agreed to  in writing,  software  distributed under
 * the License is distributed on an "AS IS" BASIS,  WITHOUT WARRANTIES OR
 * CONDITIONS OF  ANY KIND, either  express or implied.  See  the License
 * for the specific language governing permissions  and limitations under
 * the License.
 * 
 **************************************************************************/

// this may be the "native" header that comes with the compiler
// do not assume that any of our stuff (i.e., macros) is available

#if defined (__IBMCPP__) && !defined (_RWSTD_NO_IMPLICIT_INCLUSION)
// Disable implicit inclusion to work around 
// a limitation in IBM's VisualAge 5.0.2.0 (see PR#26959) 

#  define _RWSTD_NO_IMPLICIT_INCLUSION 
#endif

#include <cstdlib>
#include <cmath>

#include <any.h>
#include <driver.h>
#include <valcmp.h>
#include"std_log_result.h"
#define LOG_FILENAME_LINE __FILE__, __LINE__
int failures=0;


// define function templates with the same signatures as
// the required overloads; if the required overloads are
// not defined, the corresponding specializations of the
// function templates will be instantiated and called,
// triggering an assertion

#define FUN_1(name)                                                     \
    template <class T>                                                  \
    T name (T) {                                                        \
        static const char* const tname = rw_any_t (T ()).type_name ();    \
        rw_assert (0, 0, __LINE__, "std::%s(%s) not declared\n",        \
                   #name, tname);                                       \
        return T ();                                                    \
    } typedef void unused_typedef

#define FUN_2(name)                                                     \
    template <class T>                                                  \
    T name (T, T) {                                                     \
        static const char* const tname = rw_any_t (T ()).type_name ();    \
        rw_assert (0, 0, __LINE__, "std::%s (%s, %s) not declared\n",   \
                   #name, tname, tname);                                \
        return T ();                                                    \
    } typedef void unused_typedef

#define FUN_2_PTR(name)                                                 \
    template <class T>                                                  \
    T name (T, T*) {                                                    \
        static const char* const tname = rw_any_t (T ()).type_name ();    \
        rw_assert (0, 0, __LINE__, "std::%s (%s, %s*) not declared\n",  \
                   #name, tname, tname);                                \
        return T ();                                                    \
    } typedef void unused_typedef

#define FUN_2_INT(name)                                                 \
    template <class T>                                                  \
    T name (T, int) {                                                   \
        static const char* const tname = rw_any_t (T ()).type_name ();    \
        rw_assert (0, 0, __LINE__, "std::%s (%s, int) not declared\n",  \
                   #name, tname);                                       \
        return T ();                                                    \
    } typedef void unused_typedef

#define FUN_2_PINT(name)                                                \
    template <class T>                                                  \
    T name (T, int*) {                                                  \
        static const char* const tname = rw_any_t (T ()).type_name ();    \
        rw_assert (0, 0, __LINE__, "std::%s (%s, int*) not declared\n", \
                   #name, tname);                                       \
        return T ();                                                    \
    } typedef void unused_typedef


_RWSTD_NAMESPACE (std) {

// abs() is not declared in the C header <math.h> but is required
// to be declared in the C++ headers <math.h> and <cmath>
FUN_1 (abs);
FUN_1 (acos);
FUN_1 (asin);
FUN_1 (atan);
FUN_2 (atan2);
FUN_1 (ceil);
FUN_1 (cos);
FUN_1 (cosh);
FUN_1 (div);
FUN_1 (exp);
FUN_1 (fabs);
FUN_1 (floor);
FUN_2 (fmod);
FUN_2_PINT (frexp);
FUN_2_INT (ldexp);
FUN_1 (log);
FUN_1 (log10);
FUN_2_PTR (modf);
FUN_2 (pow);
FUN_2_INT (pow);
FUN_1 (sin);
FUN_1 (sinh);
FUN_1 (sqrt);
FUN_1 (tan);
FUN_1 (tanh);

}   // namespace std


// returns true if all `size' bytes starting at `s' are 0
static bool
check_bits (const char *s, unsigned size)
{
    while (size-- && !s [size]);
    return unsigned (-1) == size;
}


static void
clear_bytes (void *pb, _RWSTD_SIZE_T size)
{
    for (_RWSTD_SIZE_T i = 0; i != size; ++i)
        ((char*)pb)[i] = 0;
}


static void
test_behavior ()
{
    union {
        float       f;
        double      d;

#ifndef _RWSTD_NO_LONG_DOUBLE
        long double l;
#endif   // _RWSTD_NO_LONG_DOUBLE

        char buf [sizeof (long double) * 2];
    } u;

#if !defined (__SUNPRO_CC) || __SUNPRO_CC > 0x530

    // make sure functions do not overflow buffer
    clear_bytes (u.buf, sizeof u);
    const float f = std::modf (3.141592f, &u.f);
    if(!( 3000 == int (u.f * 1000) && 141592 == int (f * 1000000)
               && check_bits (u.buf + sizeof u.f, sizeof u - sizeof u.f))) 
     {
       failures++;
       std_log(LOG_FILENAME_LINE,"Reason: Failing modf function");
      }
  
      rw_assert (   3000 == int (u.f * 1000) && 141592 == int (f * 1000000)
               && check_bits (u.buf + sizeof u.f, sizeof u - sizeof u.f),
               0, __LINE__, "float std::modf (float)");

#endif   // SunPro > 5.3

    clear_bytes (u.buf, sizeof u);
    const double d = std::modf (3.1415926, &u.d);
    
    if(!(3000 == int (u.d * 1000) && 1415926 == int (d * 10000000)
               && check_bits (u.buf + sizeof u.d, sizeof u - sizeof u.d))) 
     {
       failures++;
       std_log(LOG_FILENAME_LINE,"Reason: Failing modf function");
      }
    rw_assert (   3000 == int (u.d * 1000) && 1415926 == int (d * 10000000)
               && check_bits (u.buf + sizeof u.d, sizeof u - sizeof u.d),
               0, __LINE__, "double std::modf (double)");

#ifndef __SYMBIAN32__
#ifndef _RWSTD_NO_LONG_DOUBLE

#  if !defined (__SUNPRO_CC) || __SUNPRO_CC > 0x530

    clear_bytes (u.buf, sizeof u);
    const long double l = std::modf (3.1415926L, &u.l);
     bool test=check_bits (u.buf + sizeof u.l, sizeof u - sizeof u.l);
     if(!(3000 == int (u.l * 1000) && 1415926 == int (l * 10000000)
               && test)) 
     {
       failures++;
       std_log(LOG_FILENAME_LINE,"Reason: Failing modf function");
      }
    rw_assert (   3000 == int (u.l * 1000) && 1415926 == int (l * 10000000)
               && check_bits (u.buf + sizeof u.l, sizeof u - sizeof u.l),
               0, __LINE__, "long double std::modf (long double)");

#  endif   // SunPro > 5.3

#endif   // _RWSTD_NO_LONG_DOUBLE
#endif // __SYMBIAN32__


    // check overloads of std::pow()
    for (int i = -10; i != 10; ++i) {
        for (int j = -10; j != 10; ++j) {

            if (-9 < j && j < 9) {
                // verify that both versions are equivalent
                const float xf = std::pow (float (i), int (j));
                const float yf = std::pow (float (i), float (j));
                       
                 if(!(rw_equal (xf, yf) || !i && j < 0))
                 {
                   failures++;
                   std_log(LOG_FILENAME_LINE,"Reason: Failing pow function for i=%d,j=%d",i,j);
                 }
                  
                rw_assert (rw_equal (xf, yf) || !i && j < 0,
                           0, __LINE__,
                           "std::pow (%d.0f, %d) = %g, "
                           "std::pow (%d,0f, %d.0f) = %g",
                           i, j, xf, i, j, yf);
            }

            const float xd = std::pow (double (i), int (j));
            const float yd = std::pow (double (i), double (j));

			  if(!(rw_equal (xd, yd) || !i && j < 0))
			                 {
			                   failures++;
			                    std_log(LOG_FILENAME_LINE,"Reason: Failing pow function for i=%d,j=%d",i,j);
			                 }

            rw_assert (rw_equal (xd, yd) || !i && j < 0,
                       0, __LINE__,
                       "std::pow (%d.0, %d) = %g, "
                       "std::pow (%d.0, %d.0) = %g",
                       i, j, xd, i, j, yd);

#ifndef _RWSTD_NO_LONG_DOUBLE

            const long double xl = std::pow ((long double)i, int (j));
            const long double yl = std::pow ((long double)i, (long double)j);
            
            if(!(rw_equal (xl, yl) || !i && j < 0))
			                 {
			                   failures++;
			                    std_log(LOG_FILENAME_LINE,"Reason: Failing pow function ");
			                 }

        
            rw_assert (rw_equal (xl, yl) || !i && j < 0,
                       0, __LINE__,
                       "std::pow (%d.0L, %d) = %Lg, "
                       "std::pow (%d.0L, %d.0L) = %Lg",
                       i, j, xl, i, j, yl);

#endif   // _RWSTD_NO_LONG_DOUBLE

        }
    }
}


static void
test_declarations ()
{
    _USING(namespace std);

    int i = 1;
    long l = 1;

    float f = 0.1;
    double d = 0.1;

#ifndef _RWSTD_NO_LONG_DOUBLE

    long double ld = 0.1;

#  define CHECK_OVERLOADS(name)                                         \
          rw_info (0, 0, __LINE__, "std::%s() overloads ", #name);      \
          (void)name (f);                                               \
          (void)name (d);                                               \
          (void)name (ld)
#else   // if defined (_RWSTD_NO_LONG_DOUBLE)
#  define CHECK_OVERLOADS(name)                                         \
          rw_info (0, 0, __LINE__, "std::%s() overloads", #name);       \
          (void)name (f);                                               \
          (void)name (d)
#endif   // _RWSTD_NO_LONG_DOUBLE

    CHECK_OVERLOADS (abs);
    CHECK_OVERLOADS (acos);
    CHECK_OVERLOADS (asin);
    CHECK_OVERLOADS (atan);
    CHECK_OVERLOADS (atan);
    CHECK_OVERLOADS (ceil);
    CHECK_OVERLOADS (cos);
    CHECK_OVERLOADS (cosh);
    CHECK_OVERLOADS (exp);
    CHECK_OVERLOADS (fabs);
    CHECK_OVERLOADS (floor);

    rw_info (0, 0, __LINE__, "std::%s() overloads", "fmod");
    (void)fmod (f, f); (void)fmod (d, d);

    rw_info (0, 0, __LINE__, "std::%s() overloads", "frexp");
    (void)frexp (f, &i); (void)frexp (d, &i);

    rw_info (0, 0, __LINE__, "std::%s() overloads", "ldexp");
    (void)ldexp (f, i); (void)ldexp (d, i);

    CHECK_OVERLOADS (log);
    CHECK_OVERLOADS (log10);

    rw_info (0, 0, __LINE__, "std::%s() overloads", "modf");
    (void)modf (f, &f); (void)modf (d, &d);

    rw_info (0, 0, __LINE__, "std::%s() overloads", "pow");
    (void)pow (f, f); (void)pow (d, d);
    (void)pow (f, i); (void)pow (d, i);

    CHECK_OVERLOADS (sin);
    CHECK_OVERLOADS (sinh);
    CHECK_OVERLOADS (sqrt);
    CHECK_OVERLOADS (tan);
    CHECK_OVERLOADS (tanh);

#ifndef _RWSTD_NO_LONG_DOUBLE

    (void)atan2 (ld, ld);
    (void)fmod (ld, ld);
    (void)frexp (ld, &i);
    (void)ldexp (ld, i);
    (void)modf (ld, &d);
    (void)pow (ld, ld);
    (void)pow (ld, i);

#endif   // _RWSTD_NO_LONG_DOUBLE

    rw_info (0, 0, __LINE__, "std::%s() overloads", "div");
    (void)div (i, i);
    (void)div (l, l);
}

/**************************************************************************/

static int no_declarations;
static int no_behavior;


int run_test (int, char*[])
{
    if (no_declarations)
        rw_note (0, __FILE__, __LINE__, "test of declarations disabled");
    else
        test_declarations ();

    if (no_behavior)
        rw_note (0, __FILE__, __LINE__, "test of behavior disabled");
    else
        test_behavior ();

    return 0;
}

/**************************************************************************/

int main (int argc, char *argv[])
{
   std_log(LOG_FILENAME_LINE,"[Test Case for c_math]");
    
    #ifndef __SYMBIAN32__
    return rw_test (argc, argv, __FILE__,
                    "lib.c.math",
                    0 /* no comment */, run_test,
                    "|-no-declarations# |-no-behavior#",
                    &no_declarations, &no_behavior);
    #else
      rw_test (argc, argv, __FILE__,
                    "lib.c.math",
                    0 /* no comment */, run_test,
                    "|-no-declarations# |-no-behavior#",
                    &no_declarations, &no_behavior);
    if(failures)
      {
        assert_failed = true;
               std_log(LOG_FILENAME_LINE,"Result: Failed");
      }
     else
      {
       std_log(LOG_FILENAME_LINE,"Result: Passed");
      }
  
   std_log(LOG_FILENAME_LINE,"[End Test Case]");  
   
   testResultXml("26_c_math");
    close_log_file();
 #endif  
}

