/* -*- mode: c++; indent-tabs-mode: nil -*- */
/*
  Pseudo_QC_Float.qpp

  Qore Programming Language

  Copyright (C) 2003 - 2023 Qore Technologies, s.r.o.

  Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files (the "Software"),
  to deal in the Software without restriction, including without limitation
  the rights to use, copy, modify, merge, publish, distribute, sublicense,
  and/or sell copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  DEALINGS IN THE SOFTWARE.

  Note that the Qore library is released under a choice of three open-source
  licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
  information.
*/

#include <qore/Qore.h>
#include "qore/intern/qore_number_private.h"

#include <cmath>

//! Methods in this pseudo-class can be executed on @ref float "floating-point values"
/**
 */
qclass <float> [arg=double f = v.getAsFloat();vparent=<value>];

//! Returns Qore::NT_FLOAT
/**
    @return Qore::NT_FLOAT

    @par Example:
    @code{.py}
switch (f.typeCode()) {
    case NT_FLOAT:
        printf("%y: is a float\n", f);
        break;
}
    @endcode
*/
int <float>::typeCode() [flags=CONSTANT] {
   return NT_FLOAT;
}

//! Returns @ref True if the float is non-zero, @ref False if zero
/**
    @return @ref True if the float is non-zero, @ref False if zero

    @par Example:
    @code{.py}
bool b = f.val();
    @endcode

    @see
    - @ref perl-bool-eval "%perl-bool-eval"
    - @ref strict-bool-eval "%strict-bool-eval"
*/
bool <float>::val() [flags=CONSTANT] {
   return (bool)f == 0.0 ? false : true;
}

//! Returns @ref True because float values can be converted to integers
/**
    @return @ref True because float values can be converted to integers

    @par Example:
    @code{.py}
if (n.intp())
    printf("%y: can be converted to an integer: %d\n", n, int(n));
    @endcode
*/
bool <float>::intp() [flags=CONSTANT] {
   return true;
}

//! Returns @ref True because float values can be converted to strings
/**
    @return @ref True because float values can be converted to strings

    @par Example:
    @code{.py}
if (n.strp())
    printf("%y: can be converted to a string: '%s'\n", n, string(n));
    @endcode
*/
bool <float>::strp() [flags=CONSTANT] {
   return true;
}

//! Returns a string of a formatted number according to a format string
/** @param fmt the format string has the following format:\n
    <em>\<thousands_separator\></em><tt>[</tt><em>\<decimal_separator\>[\<decimals\>]</em><tt>]</tt>\n
    where:\n
    - \a thousands_separator and \a decimal_separator are single characters defining the thousands and decimal separator characters respectively, and
    - \a decimals is one or more digits defining how may decimals should appear after the decimal point; a negative number means to round that number of digits before the decimal place

    @return a string of a formatted number according to a format string; if the format string does not follow the given format, then the number without formatting is returned

    @par Example:
    @code{.py}
float f = -48392093894.2349;
string nstr = f.format(".,3"); # returns "-48.392.093.894,235"
    @endcode

    @note equivalent to format_number(string, softfloat)

    @see
    - @ref <int>::format(string)
    - @ref <number>::format(string)
    - @ref <int>::format(int, string, string)
    - @ref <float>::format(int, string, string)
    - @ref <number>::format(int, string, string)

    @since %Qore 0.8.6
 */
string <float>::format(string fmt) [flags=CONSTANT] {
   return format_float_intern(*fmt, f, xsink);
}

//! Returns a formatted string of the floating-point number according to format arguments
/** @param prec the number of digits after the decimal point; a negative value means to round that number of digits before the decimal place, whereas the special constant @ref SNF_AllDigits means to include all possible digits after the decimal point
    @param decimal_sep a single character that defines the decimal separator; an empty string means no decimal separator
    @param thousands_sep a single character that defines the thousands and further separators every three digits before the decimal point; an empty string means no thousands separator

    @return a string representing the floating-point number according to the format arguments as described above

    @par Example:
    @code{.py}
number n = -48392093894.2349n;
string nstr = n.format(3, ".", ","); # returns "-48.392.093.894,235"
    @endcode

    @see
    - @ref <number>::format(int, string, string)
    - @ref <int>::format(int, string, string)
    - @ref <number>::format(string)
    - @ref <float>::format(string)
    - @ref <int>::format(string)

    @since %Qore 0.8.13
 */
string <float>::format(int prec = 2, string decimal_sep = ".", string thousands_sep = "") [flags=RET_VALUE_ONLY] {
   return format_float_intern(prec, decimal_sep, thousands_sep, f, xsink);
}

//! Returns @ref True if the number is NaN (not a number)
/**
    @return @ref True if the number is NaN (not a number)

    @par Example:
    @code{.py}
if (f.nanp())
    print("the operation resulted in NaN\n");
    @endcode

    @since %Qore 0.8.12
*/
bool <float>::nanp() [flags=CONSTANT] {
   return std::isnan(f) != 0;
}

//! Returns @ref True if the number is infinity (+ or -)
/**
    @return @ref True if the number is infinity (+ or -)

    @par Example:
    @code{.py}
if (f.infp())
    print("the operation resulted in infinity\n");
    @endcode

    @since %Qore 0.8.12
*/
bool <float>::infp() [flags=CONSTANT] {
   return std::isinf(f) != 0;
}

//! Returns -1 if the number is negative, 0 if it is zero, or 1 if it is positive
/** @return -1 if the number is negative, 0 if it is zero, or 1 if it is positive

    @par Example:
    @code{.py}
printf("sign: %d\n", f.sign());
    @endcode

    @since %Qore 0.8.6
*/
int <float>::sign() [flags=CONSTANT] {
   if (!f)
      return 0;
   return f > 0.0 ? 1 : -1;
}

//! Returns the absolute value of the number
/** @par Example:
    @code{.py}
f = f.abs();
    @endcode

    @return the absolute value of the number

    @note equivalent to abs(float)

    @since %Qore 0.8.8
*/
float <float>::abs() [flags=CONSTANT] {
   return fabs(f);
}

//! Converts the number to a different <b>base</b> (and returns it as a string).
/** @param base the base to convert the number to; this value must be 2 - 36 inclusive or an \c INVALID-BASE exception will be thrown

    @return the converted value as a string

    @par Example:
    @code{.py}
          (15.5).toBase(20));   // returns "F.A"
         (-13.8).toBase(20));   // returns "-D.G"
         (21.48).toBase(15));   // returns "16.73"
    @endcode

    @throw INVALID-BASE the base is invalid; must be 2 - 36 inclusive

    @see \link <int>::toBase(int base) \endlink
    @see \link <number>::toBase(int base) \endlink

    @since %Qore 0.8.13
*/
string <float>::toBase(int base = 10) [flags=RET_VALUE_ONLY] {
    return qore_number_private::toBase(f, base, xsink);
}
