sc_fxval.cc revision 12854
112854Sgabeblack@google.com/*****************************************************************************
212854Sgabeblack@google.com
312854Sgabeblack@google.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
412854Sgabeblack@google.com  more contributor license agreements.  See the NOTICE file distributed
512854Sgabeblack@google.com  with this work for additional information regarding copyright ownership.
612854Sgabeblack@google.com  Accellera licenses this file to you under the Apache License, Version 2.0
712854Sgabeblack@google.com  (the "License"); you may not use this file except in compliance with the
812854Sgabeblack@google.com  License.  You may obtain a copy of the License at
912854Sgabeblack@google.com
1012854Sgabeblack@google.com    http://www.apache.org/licenses/LICENSE-2.0
1112854Sgabeblack@google.com
1212854Sgabeblack@google.com  Unless required by applicable law or agreed to in writing, software
1312854Sgabeblack@google.com  distributed under the License is distributed on an "AS IS" BASIS,
1412854Sgabeblack@google.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1512854Sgabeblack@google.com  implied.  See the License for the specific language governing
1612854Sgabeblack@google.com  permissions and limitations under the License.
1712854Sgabeblack@google.com
1812854Sgabeblack@google.com *****************************************************************************/
1912854Sgabeblack@google.com
2012854Sgabeblack@google.com/*****************************************************************************
2112854Sgabeblack@google.com
2212854Sgabeblack@google.com  sc_fxval.cpp -
2312854Sgabeblack@google.com
2412854Sgabeblack@google.com  Original Author: Martin Janssen, Synopsys, Inc.
2512854Sgabeblack@google.com
2612854Sgabeblack@google.com *****************************************************************************/
2712854Sgabeblack@google.com
2812854Sgabeblack@google.com/*****************************************************************************
2912854Sgabeblack@google.com
3012854Sgabeblack@google.com  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
3112854Sgabeblack@google.com  changes you are making here.
3212854Sgabeblack@google.com
3312854Sgabeblack@google.com      Name, Affiliation, Date:
3412854Sgabeblack@google.com  Description of Modification:
3512854Sgabeblack@google.com
3612854Sgabeblack@google.com *****************************************************************************/
3712854Sgabeblack@google.com
3812854Sgabeblack@google.com
3912854Sgabeblack@google.com// $Log: sc_fxval.cpp,v $
4012854Sgabeblack@google.com// Revision 1.1.1.1  2006/12/15 20:20:04  acg
4112854Sgabeblack@google.com// SystemC 2.3
4212854Sgabeblack@google.com//
4312854Sgabeblack@google.com// Revision 1.3  2006/01/13 18:53:58  acg
4412854Sgabeblack@google.com// Andy Goodrich: added $Log command so that CVS comments are reproduced in
4512854Sgabeblack@google.com// the source.
4612854Sgabeblack@google.com//
4712854Sgabeblack@google.com
4812854Sgabeblack@google.com#include <cctype>
4912854Sgabeblack@google.com#include <cfloat>
5012854Sgabeblack@google.com#include <cmath>
5112854Sgabeblack@google.com#include <cstdlib>
5212854Sgabeblack@google.com
5312854Sgabeblack@google.com#include "systemc/ext/dt/fx/sc_fxval.hh"
5412854Sgabeblack@google.com
5512854Sgabeblack@google.comnamespace sc_dt
5612854Sgabeblack@google.com{
5712854Sgabeblack@google.com
5812854Sgabeblack@google.com// ----------------------------------------------------------------------------
5912854Sgabeblack@google.com//  CLASS : sc_fxval
6012854Sgabeblack@google.com//
6112854Sgabeblack@google.com//  Fixed-point value type; arbitrary precision.
6212854Sgabeblack@google.com// ----------------------------------------------------------------------------
6312854Sgabeblack@google.com
6412854Sgabeblack@google.com// explicit conversion to character string
6512854Sgabeblack@google.com
6612854Sgabeblack@google.comconst std::string
6712854Sgabeblack@google.comsc_fxval::to_string() const
6812854Sgabeblack@google.com{
6912854Sgabeblack@google.com    return std::string(m_rep->to_string(SC_DEC, -1, SC_E));
7012854Sgabeblack@google.com}
7112854Sgabeblack@google.com
7212854Sgabeblack@google.comconst std::string
7312854Sgabeblack@google.comsc_fxval::to_string(sc_numrep numrep) const
7412854Sgabeblack@google.com{
7512854Sgabeblack@google.com    return std::string(m_rep->to_string(numrep, -1, SC_E));
7612854Sgabeblack@google.com}
7712854Sgabeblack@google.com
7812854Sgabeblack@google.comconst std::string
7912854Sgabeblack@google.comsc_fxval::to_string(sc_numrep numrep, bool w_prefix) const
8012854Sgabeblack@google.com{
8112854Sgabeblack@google.com    return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), SC_E));
8212854Sgabeblack@google.com}
8312854Sgabeblack@google.com
8412854Sgabeblack@google.comconst std::string
8512854Sgabeblack@google.comsc_fxval::to_string(sc_fmt fmt) const
8612854Sgabeblack@google.com{
8712854Sgabeblack@google.com    return std::string(m_rep->to_string(SC_DEC, -1, fmt));
8812854Sgabeblack@google.com}
8912854Sgabeblack@google.com
9012854Sgabeblack@google.comconst std::string
9112854Sgabeblack@google.comsc_fxval::to_string(sc_numrep numrep, sc_fmt fmt) const
9212854Sgabeblack@google.com{
9312854Sgabeblack@google.com    return std::string(m_rep->to_string(numrep, -1, fmt));
9412854Sgabeblack@google.com}
9512854Sgabeblack@google.com
9612854Sgabeblack@google.comconst std::string
9712854Sgabeblack@google.comsc_fxval::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const
9812854Sgabeblack@google.com{
9912854Sgabeblack@google.com    return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), fmt));
10012854Sgabeblack@google.com}
10112854Sgabeblack@google.com
10212854Sgabeblack@google.com
10312854Sgabeblack@google.comconst std::string
10412854Sgabeblack@google.comsc_fxval::to_dec() const
10512854Sgabeblack@google.com{
10612854Sgabeblack@google.com    return std::string(m_rep->to_string(SC_DEC, -1, SC_E));
10712854Sgabeblack@google.com}
10812854Sgabeblack@google.com
10912854Sgabeblack@google.comconst std::string
11012854Sgabeblack@google.comsc_fxval::to_bin() const
11112854Sgabeblack@google.com{
11212854Sgabeblack@google.com    return std::string(m_rep->to_string(SC_BIN, -1, SC_E));
11312854Sgabeblack@google.com}
11412854Sgabeblack@google.com
11512854Sgabeblack@google.comconst std::string
11612854Sgabeblack@google.comsc_fxval::to_oct() const
11712854Sgabeblack@google.com{
11812854Sgabeblack@google.com    return std::string(m_rep->to_string(SC_OCT, -1, SC_E));
11912854Sgabeblack@google.com}
12012854Sgabeblack@google.com
12112854Sgabeblack@google.comconst std::string
12212854Sgabeblack@google.comsc_fxval::to_hex() const
12312854Sgabeblack@google.com{
12412854Sgabeblack@google.com    return std::string(m_rep->to_string(SC_HEX, -1, SC_E));
12512854Sgabeblack@google.com}
12612854Sgabeblack@google.com
12712854Sgabeblack@google.com
12812854Sgabeblack@google.com// print or dump content
12912854Sgabeblack@google.com
13012854Sgabeblack@google.comvoid sc_fxval::print(::std::ostream &os) const { m_rep->print(os); }
13112854Sgabeblack@google.com
13212854Sgabeblack@google.comvoid
13312854Sgabeblack@google.comsc_fxval::scan(::std::istream &is)
13412854Sgabeblack@google.com{
13512854Sgabeblack@google.com    std::string s;
13612854Sgabeblack@google.com    is >> s;
13712854Sgabeblack@google.com    *this = s.c_str();
13812854Sgabeblack@google.com}
13912854Sgabeblack@google.com
14012854Sgabeblack@google.comvoid
14112854Sgabeblack@google.comsc_fxval::dump(::std::ostream &os) const
14212854Sgabeblack@google.com{
14312854Sgabeblack@google.com    os << "sc_fxval" << ::std::endl;
14412854Sgabeblack@google.com    os << "(" << ::std::endl;
14512854Sgabeblack@google.com    os << "rep = ";
14612854Sgabeblack@google.com    m_rep->dump(os);
14712854Sgabeblack@google.com    // TO BE COMPLETED
14812854Sgabeblack@google.com    // os << "r_flag   = " << m_r_flag << ::std::endl;
14912854Sgabeblack@google.com    // os << "observer = ";
15012854Sgabeblack@google.com    // if (m_observer != 0)
15112854Sgabeblack@google.com    //     m_observer->dump(os);
15212854Sgabeblack@google.com    // else
15312854Sgabeblack@google.com    //     os << "0" << ::std::endl;
15412854Sgabeblack@google.com    os << ")" << ::std::endl;
15512854Sgabeblack@google.com}
15612854Sgabeblack@google.com
15712854Sgabeblack@google.com// protected methods and friend functions
15812854Sgabeblack@google.comsc_fxval_observer *
15912854Sgabeblack@google.comsc_fxval::lock_observer() const
16012854Sgabeblack@google.com{
16112854Sgabeblack@google.com    SC_ASSERT_(m_observer != 0, "lock observer failed");
16212854Sgabeblack@google.com    sc_fxval_observer *tmp = m_observer;
16312854Sgabeblack@google.com    m_observer = 0;
16412854Sgabeblack@google.com    return tmp;
16512854Sgabeblack@google.com}
16612854Sgabeblack@google.com
16712854Sgabeblack@google.comvoid
16812854Sgabeblack@google.comsc_fxval::unlock_observer(sc_fxval_observer *observer_) const
16912854Sgabeblack@google.com{
17012854Sgabeblack@google.com    SC_ASSERT_(observer_ != 0, "unlock observer failed");
17112854Sgabeblack@google.com    m_observer = observer_;
17212854Sgabeblack@google.com}
17312854Sgabeblack@google.com
17412854Sgabeblack@google.com
17512854Sgabeblack@google.com// ----------------------------------------------------------------------------
17612854Sgabeblack@google.com//  CLASS : sc_fxval_fast
17712854Sgabeblack@google.com//
17812854Sgabeblack@google.com//  Fixed-point value types; limited precision.
17912854Sgabeblack@google.com// ----------------------------------------------------------------------------
18012854Sgabeblack@google.com
18112854Sgabeblack@google.comstatic void
18212854Sgabeblack@google.comprint_dec(scfx_string &s, scfx_ieee_double id, int w_prefix, sc_fmt fmt)
18312854Sgabeblack@google.com{
18412854Sgabeblack@google.com    if (id.negative() != 0) {
18512854Sgabeblack@google.com        id.negative(0);
18612854Sgabeblack@google.com        s += '-';
18712854Sgabeblack@google.com    }
18812854Sgabeblack@google.com
18912854Sgabeblack@google.com    if (w_prefix == 1) {
19012854Sgabeblack@google.com        scfx_print_prefix(s, SC_DEC);
19112854Sgabeblack@google.com    }
19212854Sgabeblack@google.com
19312854Sgabeblack@google.com    if (id.is_zero()) {
19412854Sgabeblack@google.com        s += '0';
19512854Sgabeblack@google.com        return;
19612854Sgabeblack@google.com    }
19712854Sgabeblack@google.com
19812854Sgabeblack@google.com    // split 'id' into its integer and fractional part
19912854Sgabeblack@google.com    double int_part;
20012854Sgabeblack@google.com    double frac_part = std::modf(static_cast<double>(id), &int_part);
20112854Sgabeblack@google.com
20212854Sgabeblack@google.com    int i;
20312854Sgabeblack@google.com
20412854Sgabeblack@google.com    // print integer part
20512854Sgabeblack@google.com    int int_digits = 0;
20612854Sgabeblack@google.com    int int_zeros  = 0;
20712854Sgabeblack@google.com
20812854Sgabeblack@google.com    if (int_part != 0.0) {
20912854Sgabeblack@google.com        int_digits = (int)std::ceil(std::log10(int_part + 1.0));
21012854Sgabeblack@google.com
21112854Sgabeblack@google.com        int len = s.length();
21212854Sgabeblack@google.com        s.append(int_digits);
21312854Sgabeblack@google.com
21412854Sgabeblack@google.com        bool zero_digits = (frac_part == 0.0 && fmt != SC_F);
21512854Sgabeblack@google.com
21612854Sgabeblack@google.com        for (i = int_digits + len - 1; i >= len; i--) {
21712854Sgabeblack@google.com            unsigned int remainder = (unsigned int)std::fmod(int_part, 10.0);
21812854Sgabeblack@google.com            s[i] = static_cast<char>('0' + remainder);
21912854Sgabeblack@google.com
22012854Sgabeblack@google.com            if (zero_digits) {
22112854Sgabeblack@google.com                if (remainder == 0)
22212854Sgabeblack@google.com                    int_zeros++;
22312854Sgabeblack@google.com                else
22412854Sgabeblack@google.com                    zero_digits = false;
22512854Sgabeblack@google.com            }
22612854Sgabeblack@google.com
22712854Sgabeblack@google.com            int_part /= 10.0;
22812854Sgabeblack@google.com        }
22912854Sgabeblack@google.com
23012854Sgabeblack@google.com        // discard trailing zeros from int_part
23112854Sgabeblack@google.com        s.discard(int_zeros);
23212854Sgabeblack@google.com
23312854Sgabeblack@google.com        if (s[len] == '0') {
23412854Sgabeblack@google.com            // int_digits was overestimated by one
23512854Sgabeblack@google.com            s.remove(len);
23612854Sgabeblack@google.com            --int_digits;
23712854Sgabeblack@google.com        }
23812854Sgabeblack@google.com    }
23912854Sgabeblack@google.com
24012854Sgabeblack@google.com    // print fractional part
24112854Sgabeblack@google.com    int frac_digits = 0;
24212854Sgabeblack@google.com    int frac_zeros  = 0;
24312854Sgabeblack@google.com
24412854Sgabeblack@google.com    if (frac_part != 0.0) {
24512854Sgabeblack@google.com        s += '.';
24612854Sgabeblack@google.com
24712854Sgabeblack@google.com        bool zero_digits = (int_digits == 0 && fmt != SC_F);
24812854Sgabeblack@google.com
24912854Sgabeblack@google.com        frac_zeros = (int)std::floor(-std::log10(frac_part + DBL_EPSILON));
25012854Sgabeblack@google.com
25112854Sgabeblack@google.com        frac_part *= std::pow(10.0, frac_zeros);
25212854Sgabeblack@google.com
25312854Sgabeblack@google.com        frac_digits = frac_zeros;
25412854Sgabeblack@google.com        if (!zero_digits) {
25512854Sgabeblack@google.com            for (i = 0; i < frac_zeros; i++)
25612854Sgabeblack@google.com                s += '0';
25712854Sgabeblack@google.com            frac_zeros = 0;
25812854Sgabeblack@google.com        }
25912854Sgabeblack@google.com
26012854Sgabeblack@google.com        while (frac_part != 0.0) {
26112854Sgabeblack@google.com            frac_part *= 10.0;
26212854Sgabeblack@google.com            int n = static_cast<int>(frac_part);
26312854Sgabeblack@google.com
26412854Sgabeblack@google.com            if (zero_digits) {
26512854Sgabeblack@google.com                if (n == 0)
26612854Sgabeblack@google.com                    frac_zeros++;
26712854Sgabeblack@google.com                else
26812854Sgabeblack@google.com                    zero_digits = false;
26912854Sgabeblack@google.com            }
27012854Sgabeblack@google.com
27112854Sgabeblack@google.com            if (!zero_digits)
27212854Sgabeblack@google.com                s += static_cast<char>('0' + n);
27312854Sgabeblack@google.com
27412854Sgabeblack@google.com            frac_part -= n;
27512854Sgabeblack@google.com            frac_digits++;
27612854Sgabeblack@google.com        }
27712854Sgabeblack@google.com    }
27812854Sgabeblack@google.com
27912854Sgabeblack@google.com    // print exponent
28012854Sgabeblack@google.com    if (fmt != SC_F) {
28112854Sgabeblack@google.com        if (frac_digits == 0)
28212854Sgabeblack@google.com            scfx_print_exp(s, int_zeros);
28312854Sgabeblack@google.com        else if (int_digits == 0)
28412854Sgabeblack@google.com            scfx_print_exp(s, -frac_zeros);
28512854Sgabeblack@google.com    }
28612854Sgabeblack@google.com}
28712854Sgabeblack@google.com
28812854Sgabeblack@google.comstatic void
28912854Sgabeblack@google.comprint_other(scfx_string &s, const scfx_ieee_double &id, sc_numrep numrep,
29012854Sgabeblack@google.com             int w_prefix, sc_fmt fmt, const scfx_params *params)
29112854Sgabeblack@google.com{
29212854Sgabeblack@google.com    scfx_ieee_double id2 = id;
29312854Sgabeblack@google.com
29412854Sgabeblack@google.com    sc_numrep numrep2 = numrep;
29512854Sgabeblack@google.com
29612854Sgabeblack@google.com    bool numrep_is_sm = (numrep == SC_BIN_SM ||
29712854Sgabeblack@google.com                         numrep == SC_OCT_SM ||
29812854Sgabeblack@google.com                         numrep == SC_HEX_SM);
29912854Sgabeblack@google.com
30012854Sgabeblack@google.com    if (numrep_is_sm) {
30112854Sgabeblack@google.com        if (id2.negative() != 0) {
30212854Sgabeblack@google.com            s += '-';
30312854Sgabeblack@google.com            id2.negative(0);
30412854Sgabeblack@google.com        }
30512854Sgabeblack@google.com        switch (numrep) {
30612854Sgabeblack@google.com          case SC_BIN_SM:
30712854Sgabeblack@google.com            numrep2 = SC_BIN_US;
30812854Sgabeblack@google.com            break;
30912854Sgabeblack@google.com          case SC_OCT_SM:
31012854Sgabeblack@google.com            numrep2 = SC_OCT_US;
31112854Sgabeblack@google.com            break;
31212854Sgabeblack@google.com          case SC_HEX_SM:
31312854Sgabeblack@google.com            numrep2 = SC_HEX_US;
31412854Sgabeblack@google.com            break;
31512854Sgabeblack@google.com          default:
31612854Sgabeblack@google.com            ;
31712854Sgabeblack@google.com        }
31812854Sgabeblack@google.com    }
31912854Sgabeblack@google.com
32012854Sgabeblack@google.com    if (w_prefix != 0) {
32112854Sgabeblack@google.com        scfx_print_prefix(s, numrep);
32212854Sgabeblack@google.com    }
32312854Sgabeblack@google.com
32412854Sgabeblack@google.com    numrep = numrep2;
32512854Sgabeblack@google.com
32612854Sgabeblack@google.com    sc_fxval_fast a(id2);
32712854Sgabeblack@google.com
32812854Sgabeblack@google.com    int msb, lsb;
32912854Sgabeblack@google.com
33012854Sgabeblack@google.com    if (params != 0) {
33112854Sgabeblack@google.com        msb = params->iwl() - 1;
33212854Sgabeblack@google.com        lsb = params->iwl() - params->wl();
33312854Sgabeblack@google.com
33412854Sgabeblack@google.com        if (params->enc() == SC_TC_ &&
33512854Sgabeblack@google.com            (numrep == SC_BIN_US ||
33612854Sgabeblack@google.com              numrep == SC_OCT_US ||
33712854Sgabeblack@google.com              numrep == SC_HEX_US) &&
33812854Sgabeblack@google.com            !numrep_is_sm &&
33912854Sgabeblack@google.com            params->wl() > 1) {
34012854Sgabeblack@google.com            --msb;
34112854Sgabeblack@google.com        } else if (params->enc() == SC_US_ &&
34212854Sgabeblack@google.com            (numrep == SC_BIN ||
34312854Sgabeblack@google.com              numrep == SC_OCT ||
34412854Sgabeblack@google.com              numrep == SC_HEX ||
34512854Sgabeblack@google.com              numrep == SC_CSD)) {
34612854Sgabeblack@google.com            ++msb;
34712854Sgabeblack@google.com        }
34812854Sgabeblack@google.com    } else {
34912854Sgabeblack@google.com        if (a.is_zero()) {
35012854Sgabeblack@google.com            msb = 0;
35112854Sgabeblack@google.com            lsb = 0;
35212854Sgabeblack@google.com        } else {
35312854Sgabeblack@google.com            msb = id2.exponent() + 1;
35412854Sgabeblack@google.com            while (a.get_bit(msb) == a.get_bit(msb - 1))
35512854Sgabeblack@google.com                --msb;
35612854Sgabeblack@google.com
35712854Sgabeblack@google.com            if (numrep == SC_BIN_US ||
35812854Sgabeblack@google.com                numrep == SC_OCT_US ||
35912854Sgabeblack@google.com                numrep == SC_HEX_US) {
36012854Sgabeblack@google.com                --msb;
36112854Sgabeblack@google.com            }
36212854Sgabeblack@google.com
36312854Sgabeblack@google.com            lsb = id2.exponent() - 52;
36412854Sgabeblack@google.com            while (!a.get_bit(lsb))
36512854Sgabeblack@google.com                ++lsb;
36612854Sgabeblack@google.com        }
36712854Sgabeblack@google.com    }
36812854Sgabeblack@google.com
36912854Sgabeblack@google.com    int step;
37012854Sgabeblack@google.com
37112854Sgabeblack@google.com    switch (numrep) {
37212854Sgabeblack@google.com      case SC_BIN:
37312854Sgabeblack@google.com      case SC_BIN_US:
37412854Sgabeblack@google.com      case SC_CSD:
37512854Sgabeblack@google.com        step = 1;
37612854Sgabeblack@google.com       break;
37712854Sgabeblack@google.com      case SC_OCT:
37812854Sgabeblack@google.com      case SC_OCT_US:
37912854Sgabeblack@google.com        step = 3;
38012854Sgabeblack@google.com        break;
38112854Sgabeblack@google.com      case SC_HEX:
38212854Sgabeblack@google.com      case SC_HEX_US:
38312854Sgabeblack@google.com        step = 4;
38412854Sgabeblack@google.com        break;
38512854Sgabeblack@google.com      default:
38612854Sgabeblack@google.com        SC_REPORT_FATAL("assertion failed", "unexpected sc_numrep");
38712854Sgabeblack@google.com        sc_core::sc_abort();
38812854Sgabeblack@google.com    }
38912854Sgabeblack@google.com
39012854Sgabeblack@google.com    msb = (int)std::ceil(double(msb + 1) / step) * step - 1;
39112854Sgabeblack@google.com
39212854Sgabeblack@google.com    lsb = (int)std::floor(double(lsb) / step) * step;
39312854Sgabeblack@google.com
39412854Sgabeblack@google.com    if (msb < 0) {
39512854Sgabeblack@google.com        s += '.';
39612854Sgabeblack@google.com        if (fmt == SC_F) {
39712854Sgabeblack@google.com            int sign = (id2.negative() != 0) ? (1 << step) - 1 : 0;
39812854Sgabeblack@google.com            for (int i = (msb + 1) / step; i < 0; i++) {
39912854Sgabeblack@google.com                if (sign < 10)
40012854Sgabeblack@google.com                    s += static_cast<char>(sign + '0');
40112854Sgabeblack@google.com                else
40212854Sgabeblack@google.com                    s += static_cast<char>(sign + 'a' - 10);
40312854Sgabeblack@google.com            }
40412854Sgabeblack@google.com        }
40512854Sgabeblack@google.com    }
40612854Sgabeblack@google.com
40712854Sgabeblack@google.com    int i = msb;
40812854Sgabeblack@google.com    while (i >= lsb) {
40912854Sgabeblack@google.com        int value = 0;
41012854Sgabeblack@google.com        for (int j = step - 1; j >= 0; --j) {
41112854Sgabeblack@google.com            value += static_cast<int>(a.get_bit(i)) << j;
41212854Sgabeblack@google.com            --i;
41312854Sgabeblack@google.com        }
41412854Sgabeblack@google.com        if (value < 10)
41512854Sgabeblack@google.com            s += static_cast<char>(value + '0');
41612854Sgabeblack@google.com        else
41712854Sgabeblack@google.com            s += static_cast<char>(value + 'a' - 10);
41812854Sgabeblack@google.com        if (i == -1)
41912854Sgabeblack@google.com            s += '.';
42012854Sgabeblack@google.com    }
42112854Sgabeblack@google.com
42212854Sgabeblack@google.com    if (lsb > 0 && fmt == SC_F) {
42312854Sgabeblack@google.com        for (int i = lsb / step; i > 0; i--)
42412854Sgabeblack@google.com            s += '0';
42512854Sgabeblack@google.com    }
42612854Sgabeblack@google.com
42712854Sgabeblack@google.com    if (s[s.length() - 1] == '.')
42812854Sgabeblack@google.com        s.discard(1);
42912854Sgabeblack@google.com
43012854Sgabeblack@google.com    if (fmt != SC_F) {
43112854Sgabeblack@google.com        if (msb < 0)
43212854Sgabeblack@google.com            scfx_print_exp(s, (msb + 1) / step);
43312854Sgabeblack@google.com        else if (lsb > 0)
43412854Sgabeblack@google.com            scfx_print_exp(s, lsb / step);
43512854Sgabeblack@google.com    }
43612854Sgabeblack@google.com
43712854Sgabeblack@google.com    if (numrep == SC_CSD)
43812854Sgabeblack@google.com        scfx_tc2csd(s, w_prefix);
43912854Sgabeblack@google.com}
44012854Sgabeblack@google.com
44112854Sgabeblack@google.comconst char *
44212854Sgabeblack@google.comto_string(const scfx_ieee_double &id, sc_numrep numrep, int w_prefix,
44312854Sgabeblack@google.com          sc_fmt fmt, const scfx_params *params=0)
44412854Sgabeblack@google.com{
44512854Sgabeblack@google.com    static scfx_string s;
44612854Sgabeblack@google.com
44712854Sgabeblack@google.com    s.clear();
44812854Sgabeblack@google.com
44912854Sgabeblack@google.com    if (id.is_nan()) {
45012854Sgabeblack@google.com        scfx_print_nan(s);
45112854Sgabeblack@google.com    } else if (id.is_inf()) {
45212854Sgabeblack@google.com        scfx_print_inf(s, static_cast<bool>(id.negative()));
45312854Sgabeblack@google.com    } else if (id.negative() && !id.is_zero() &&
45412854Sgabeblack@google.com             (numrep == SC_BIN_US ||
45512854Sgabeblack@google.com               numrep == SC_OCT_US ||
45612854Sgabeblack@google.com               numrep == SC_HEX_US)) {
45712854Sgabeblack@google.com        s += "negative";
45812854Sgabeblack@google.com    } else if (numrep == SC_DEC) {
45912854Sgabeblack@google.com        sc_dt::print_dec(s, id, w_prefix, fmt);
46012854Sgabeblack@google.com    } else {
46112854Sgabeblack@google.com        sc_dt::print_other(s, id, numrep, w_prefix, fmt, params);
46212854Sgabeblack@google.com    }
46312854Sgabeblack@google.com
46412854Sgabeblack@google.com    return s;
46512854Sgabeblack@google.com}
46612854Sgabeblack@google.com
46712854Sgabeblack@google.com
46812854Sgabeblack@google.com// explicit conversion to character string
46912854Sgabeblack@google.comconst std::string
47012854Sgabeblack@google.comsc_fxval_fast::to_string() const
47112854Sgabeblack@google.com{
47212854Sgabeblack@google.com    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E));
47312854Sgabeblack@google.com}
47412854Sgabeblack@google.com
47512854Sgabeblack@google.comconst std::string
47612854Sgabeblack@google.comsc_fxval_fast::to_string(sc_numrep numrep) const
47712854Sgabeblack@google.com{
47812854Sgabeblack@google.com    return std::string(sc_dt::to_string(m_val, numrep, -1, SC_E));
47912854Sgabeblack@google.com}
48012854Sgabeblack@google.com
48112854Sgabeblack@google.comconst std::string
48212854Sgabeblack@google.comsc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix) const
48312854Sgabeblack@google.com{
48412854Sgabeblack@google.com    return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0),
48512854Sgabeblack@google.com                       SC_E));
48612854Sgabeblack@google.com}
48712854Sgabeblack@google.com
48812854Sgabeblack@google.comconst std::string
48912854Sgabeblack@google.comsc_fxval_fast::to_string(sc_fmt fmt) const
49012854Sgabeblack@google.com{
49112854Sgabeblack@google.com    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, fmt));
49212854Sgabeblack@google.com}
49312854Sgabeblack@google.com
49412854Sgabeblack@google.comconst std::string
49512854Sgabeblack@google.comsc_fxval_fast::to_string(sc_numrep numrep, sc_fmt fmt) const
49612854Sgabeblack@google.com{
49712854Sgabeblack@google.com    return std::string(sc_dt::to_string(m_val, numrep, -1, fmt));
49812854Sgabeblack@google.com}
49912854Sgabeblack@google.com
50012854Sgabeblack@google.comconst std::string
50112854Sgabeblack@google.comsc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const
50212854Sgabeblack@google.com{
50312854Sgabeblack@google.com    return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0),
50412854Sgabeblack@google.com                                        fmt));
50512854Sgabeblack@google.com}
50612854Sgabeblack@google.com
50712854Sgabeblack@google.comconst std::string
50812854Sgabeblack@google.comsc_fxval_fast::to_dec() const
50912854Sgabeblack@google.com{
51012854Sgabeblack@google.com    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E));
51112854Sgabeblack@google.com}
51212854Sgabeblack@google.com
51312854Sgabeblack@google.comconst std::string
51412854Sgabeblack@google.comsc_fxval_fast::to_bin() const
51512854Sgabeblack@google.com{
51612854Sgabeblack@google.com    return std::string(sc_dt::to_string(m_val, SC_BIN, -1, SC_E));
51712854Sgabeblack@google.com}
51812854Sgabeblack@google.com
51912854Sgabeblack@google.comconst std::string
52012854Sgabeblack@google.comsc_fxval_fast::to_oct() const
52112854Sgabeblack@google.com{
52212854Sgabeblack@google.com    return std::string(sc_dt::to_string(m_val, SC_OCT, -1, SC_E));
52312854Sgabeblack@google.com}
52412854Sgabeblack@google.com
52512854Sgabeblack@google.comconst std::string
52612854Sgabeblack@google.comsc_fxval_fast::to_hex() const
52712854Sgabeblack@google.com{
52812854Sgabeblack@google.com    return std::string(sc_dt::to_string(m_val, SC_HEX, -1, SC_E));
52912854Sgabeblack@google.com}
53012854Sgabeblack@google.com
53112854Sgabeblack@google.com
53212854Sgabeblack@google.com// print or dump content
53312854Sgabeblack@google.com
53412854Sgabeblack@google.comvoid
53512854Sgabeblack@google.comsc_fxval_fast::print(::std::ostream &os) const
53612854Sgabeblack@google.com{
53712854Sgabeblack@google.com    os << sc_dt::to_string(m_val, SC_DEC, -1, SC_E);
53812854Sgabeblack@google.com}
53912854Sgabeblack@google.com
54012854Sgabeblack@google.comvoid
54112854Sgabeblack@google.comsc_fxval_fast::scan(::std::istream &is)
54212854Sgabeblack@google.com{
54312854Sgabeblack@google.com    std::string s;
54412854Sgabeblack@google.com    is >> s;
54512854Sgabeblack@google.com    *this = s.c_str();
54612854Sgabeblack@google.com}
54712854Sgabeblack@google.com
54812854Sgabeblack@google.comvoid
54912854Sgabeblack@google.comsc_fxval_fast::dump(::std::ostream &os) const
55012854Sgabeblack@google.com{
55112854Sgabeblack@google.com    os << "sc_fxval_fast" << ::std::endl;
55212854Sgabeblack@google.com    os << "(" << ::std::endl;
55312854Sgabeblack@google.com    os << "val = " << m_val << ::std::endl;
55412854Sgabeblack@google.com    // TO BE COMPLETED
55512854Sgabeblack@google.com    // os << "r_flag   = " << m_r_flag << ::std::endl;
55612854Sgabeblack@google.com    // os << "observer = ";
55712854Sgabeblack@google.com    // if (m_observer != 0)
55812854Sgabeblack@google.com    //     m_observer->dump(os);
55912854Sgabeblack@google.com    // else
56012854Sgabeblack@google.com    //     os << "0" << ::std::endl;
56112854Sgabeblack@google.com    os << ")" << ::std::endl;
56212854Sgabeblack@google.com}
56312854Sgabeblack@google.com
56412854Sgabeblack@google.com
56512854Sgabeblack@google.com// internal use only;
56612854Sgabeblack@google.combool
56712854Sgabeblack@google.comsc_fxval_fast::get_bit(int i) const
56812854Sgabeblack@google.com{
56912854Sgabeblack@google.com    scfx_ieee_double id(m_val);
57012854Sgabeblack@google.com    if (id.is_zero() || id.is_nan() || id.is_inf())
57112854Sgabeblack@google.com        return false;
57212854Sgabeblack@google.com
57312854Sgabeblack@google.com    // convert to two's complement
57412854Sgabeblack@google.com    unsigned int m0 = id.mantissa0();
57512854Sgabeblack@google.com    unsigned int m1 = id.mantissa1();
57612854Sgabeblack@google.com
57712854Sgabeblack@google.com    if (id.is_normal())
57812854Sgabeblack@google.com        m0 += 1U << 20;
57912854Sgabeblack@google.com
58012854Sgabeblack@google.com    if (id.negative() != 0) {
58112854Sgabeblack@google.com        m0 = ~ m0;
58212854Sgabeblack@google.com        m1 = ~ m1;
58312854Sgabeblack@google.com        unsigned int tmp = m1;
58412854Sgabeblack@google.com        m1 += 1U;
58512854Sgabeblack@google.com        if (m1 <= tmp)
58612854Sgabeblack@google.com            m0 += 1U;
58712854Sgabeblack@google.com    }
58812854Sgabeblack@google.com
58912854Sgabeblack@google.com    // get the right bit
59012854Sgabeblack@google.com    int j = i - id.exponent();
59112854Sgabeblack@google.com    if ((j += 20) >= 32)
59212854Sgabeblack@google.com        return ((m0 & 1U << 31) != 0);
59312854Sgabeblack@google.com    else if (j >= 0)
59412854Sgabeblack@google.com        return ((m0 & 1U << j) != 0);
59512854Sgabeblack@google.com    else if ((j += 32) >= 0)
59612854Sgabeblack@google.com        return ((m1 & 1U << j) != 0);
59712854Sgabeblack@google.com    else
59812854Sgabeblack@google.com        return false;
59912854Sgabeblack@google.com}
60012854Sgabeblack@google.com
60112854Sgabeblack@google.com
60212854Sgabeblack@google.com// protected methods and friend functions
60312854Sgabeblack@google.comsc_fxval_fast_observer *
60412854Sgabeblack@google.comsc_fxval_fast::lock_observer() const
60512854Sgabeblack@google.com{
60612854Sgabeblack@google.com    SC_ASSERT_(m_observer != 0, "lock observer failed");
60712854Sgabeblack@google.com    sc_fxval_fast_observer *tmp = m_observer;
60812854Sgabeblack@google.com    m_observer = 0;
60912854Sgabeblack@google.com    return tmp;
61012854Sgabeblack@google.com}
61112854Sgabeblack@google.com
61212854Sgabeblack@google.comvoid
61312854Sgabeblack@google.comsc_fxval_fast::unlock_observer(sc_fxval_fast_observer *observer_) const
61412854Sgabeblack@google.com{
61512854Sgabeblack@google.com    SC_ASSERT_(observer_ != 0, "unlock observer failed");
61612854Sgabeblack@google.com    m_observer = observer_;
61712854Sgabeblack@google.com}
61812854Sgabeblack@google.com
61912854Sgabeblack@google.com#define SCFX_FAIL_IF_(cnd)                                                    \
62012854Sgabeblack@google.com{                                                                             \
62112854Sgabeblack@google.com    if ((cnd))                                                             \
62212854Sgabeblack@google.com        return static_cast<double>(scfx_ieee_double::nan());                \
62312854Sgabeblack@google.com}
62412854Sgabeblack@google.com
62512854Sgabeblack@google.comdouble
62612854Sgabeblack@google.comsc_fxval_fast::from_string(const char *s)
62712854Sgabeblack@google.com{
62812854Sgabeblack@google.com    SCFX_FAIL_IF_(s == 0 || *s == 0);
62912854Sgabeblack@google.com
63012854Sgabeblack@google.com    scfx_string s2;
63112854Sgabeblack@google.com    s2 += s;
63212854Sgabeblack@google.com    s2 += '\0';
63312854Sgabeblack@google.com
63412854Sgabeblack@google.com    bool sign_char;
63512854Sgabeblack@google.com    int sign = scfx_parse_sign(s, sign_char);
63612854Sgabeblack@google.com
63712854Sgabeblack@google.com    sc_numrep numrep = scfx_parse_prefix(s);
63812854Sgabeblack@google.com
63912854Sgabeblack@google.com    int base = 0;
64012854Sgabeblack@google.com
64112854Sgabeblack@google.com    switch (numrep) {
64212854Sgabeblack@google.com      case SC_DEC:
64312854Sgabeblack@google.com        {
64412854Sgabeblack@google.com            base = 10;
64512854Sgabeblack@google.com            if (scfx_is_nan(s)) // special case: NaN
64612854Sgabeblack@google.com                return static_cast<double>(scfx_ieee_double::nan());
64712854Sgabeblack@google.com            if (scfx_is_inf(s)) // special case: Infinity
64812854Sgabeblack@google.com                return static_cast<double>(scfx_ieee_double::inf(sign));
64912854Sgabeblack@google.com            break;
65012854Sgabeblack@google.com        }
65112854Sgabeblack@google.com      case SC_BIN:
65212854Sgabeblack@google.com      case SC_BIN_US:
65312854Sgabeblack@google.com        {
65412854Sgabeblack@google.com            SCFX_FAIL_IF_(sign_char);
65512854Sgabeblack@google.com            base = 2;
65612854Sgabeblack@google.com            break;
65712854Sgabeblack@google.com        }
65812854Sgabeblack@google.com
65912854Sgabeblack@google.com      case SC_BIN_SM:
66012854Sgabeblack@google.com        {
66112854Sgabeblack@google.com            base = 2;
66212854Sgabeblack@google.com            break;
66312854Sgabeblack@google.com        }
66412854Sgabeblack@google.com      case SC_OCT:
66512854Sgabeblack@google.com      case SC_OCT_US:
66612854Sgabeblack@google.com        {
66712854Sgabeblack@google.com            SCFX_FAIL_IF_(sign_char);
66812854Sgabeblack@google.com            base = 8;
66912854Sgabeblack@google.com            break;
67012854Sgabeblack@google.com        }
67112854Sgabeblack@google.com      case SC_OCT_SM:
67212854Sgabeblack@google.com        {
67312854Sgabeblack@google.com            base = 8;
67412854Sgabeblack@google.com            break;
67512854Sgabeblack@google.com        }
67612854Sgabeblack@google.com      case SC_HEX:
67712854Sgabeblack@google.com      case SC_HEX_US:
67812854Sgabeblack@google.com        {
67912854Sgabeblack@google.com            SCFX_FAIL_IF_(sign_char);
68012854Sgabeblack@google.com            base = 16;
68112854Sgabeblack@google.com            break;
68212854Sgabeblack@google.com        }
68312854Sgabeblack@google.com      case SC_HEX_SM:
68412854Sgabeblack@google.com        {
68512854Sgabeblack@google.com            base = 16;
68612854Sgabeblack@google.com            break;
68712854Sgabeblack@google.com        }
68812854Sgabeblack@google.com      case SC_CSD:
68912854Sgabeblack@google.com        {
69012854Sgabeblack@google.com            SCFX_FAIL_IF_(sign_char);
69112854Sgabeblack@google.com            base = 2;
69212854Sgabeblack@google.com            scfx_csd2tc(s2);
69312854Sgabeblack@google.com            s = (const char*) s2 + 4;
69412854Sgabeblack@google.com            numrep = SC_BIN;
69512854Sgabeblack@google.com            break;
69612854Sgabeblack@google.com        }
69712854Sgabeblack@google.com      default:;// Martin, what is default???
69812854Sgabeblack@google.com    }
69912854Sgabeblack@google.com
70012854Sgabeblack@google.com    //
70112854Sgabeblack@google.com    // find end of mantissa and count the digits and points
70212854Sgabeblack@google.com    //
70312854Sgabeblack@google.com
70412854Sgabeblack@google.com    const char *end = s;
70512854Sgabeblack@google.com    bool based_point = false;
70612854Sgabeblack@google.com    int int_digits = 0;
70712854Sgabeblack@google.com    int frac_digits = 0;
70812854Sgabeblack@google.com
70912854Sgabeblack@google.com    while (*end) {
71012854Sgabeblack@google.com        if (scfx_exp_start(end))
71112854Sgabeblack@google.com            break;
71212854Sgabeblack@google.com
71312854Sgabeblack@google.com        if (*end == '.') {
71412854Sgabeblack@google.com            SCFX_FAIL_IF_(based_point);
71512854Sgabeblack@google.com            based_point = true;
71612854Sgabeblack@google.com        } else {
71712854Sgabeblack@google.com            SCFX_FAIL_IF_(!scfx_is_digit(*end, numrep));
71812854Sgabeblack@google.com            if (based_point)
71912854Sgabeblack@google.com                frac_digits++;
72012854Sgabeblack@google.com            else
72112854Sgabeblack@google.com                int_digits++;
72212854Sgabeblack@google.com        }
72312854Sgabeblack@google.com
72412854Sgabeblack@google.com        end++;
72512854Sgabeblack@google.com    }
72612854Sgabeblack@google.com
72712854Sgabeblack@google.com    SCFX_FAIL_IF_(int_digits == 0 && frac_digits == 0);
72812854Sgabeblack@google.com
72912854Sgabeblack@google.com    // [ exponent ]
73012854Sgabeblack@google.com    int exponent = 0;
73112854Sgabeblack@google.com    if (*end) {
73212854Sgabeblack@google.com        for (const char *e = end + 2; *e; e++)
73312854Sgabeblack@google.com            SCFX_FAIL_IF_(!scfx_is_digit(*e, SC_DEC));
73412854Sgabeblack@google.com        exponent = std::atoi(end + 1);
73512854Sgabeblack@google.com    }
73612854Sgabeblack@google.com
73712854Sgabeblack@google.com    //
73812854Sgabeblack@google.com    // convert the mantissa
73912854Sgabeblack@google.com    //
74012854Sgabeblack@google.com    double integer = 0.0;
74112854Sgabeblack@google.com    if (int_digits != 0) {
74212854Sgabeblack@google.com        bool first_digit = true;
74312854Sgabeblack@google.com
74412854Sgabeblack@google.com        for (; s < end; s++) {
74512854Sgabeblack@google.com            if (*s == '.')
74612854Sgabeblack@google.com                break;
74712854Sgabeblack@google.com
74812854Sgabeblack@google.com            if (first_digit) {
74912854Sgabeblack@google.com                integer = scfx_to_digit(*s, numrep);
75012854Sgabeblack@google.com                switch (numrep) {
75112854Sgabeblack@google.com                  case SC_BIN:
75212854Sgabeblack@google.com                  case SC_OCT:
75312854Sgabeblack@google.com                  case SC_HEX:
75412854Sgabeblack@google.com                    {
75512854Sgabeblack@google.com                        if (integer >= (base >> 1))
75612854Sgabeblack@google.com                            integer -= base; // two's complement
75712854Sgabeblack@google.com                        break;
75812854Sgabeblack@google.com                    }
75912854Sgabeblack@google.com                  default:
76012854Sgabeblack@google.com                    ;
76112854Sgabeblack@google.com                }
76212854Sgabeblack@google.com                first_digit = false;
76312854Sgabeblack@google.com            } else {
76412854Sgabeblack@google.com                integer *= base;
76512854Sgabeblack@google.com                integer += scfx_to_digit(*s, numrep);
76612854Sgabeblack@google.com            }
76712854Sgabeblack@google.com        }
76812854Sgabeblack@google.com    }
76912854Sgabeblack@google.com
77012854Sgabeblack@google.com    // [ . fraction ]
77112854Sgabeblack@google.com    double fraction = 0.0;
77212854Sgabeblack@google.com    if (frac_digits != 0) {
77312854Sgabeblack@google.com        s++;  // skip '.'
77412854Sgabeblack@google.com
77512854Sgabeblack@google.com        bool first_digit = (int_digits == 0);
77612854Sgabeblack@google.com        double scale = 1.0;
77712854Sgabeblack@google.com        for (; s < end; s++) {
77812854Sgabeblack@google.com            scale /= base;
77912854Sgabeblack@google.com
78012854Sgabeblack@google.com            if (first_digit) {
78112854Sgabeblack@google.com                fraction = scfx_to_digit(*s, numrep);
78212854Sgabeblack@google.com                switch (numrep) {
78312854Sgabeblack@google.com                  case SC_BIN:
78412854Sgabeblack@google.com                  case SC_OCT:
78512854Sgabeblack@google.com                  case SC_HEX:
78612854Sgabeblack@google.com                    {
78712854Sgabeblack@google.com                        if (fraction >= (base >> 1))
78812854Sgabeblack@google.com                            fraction -= base; // two's complement
78912854Sgabeblack@google.com                        break;
79012854Sgabeblack@google.com                    }
79112854Sgabeblack@google.com                  default:
79212854Sgabeblack@google.com                    ;
79312854Sgabeblack@google.com                }
79412854Sgabeblack@google.com                fraction *= scale;
79512854Sgabeblack@google.com                first_digit = false;
79612854Sgabeblack@google.com            } else {
79712854Sgabeblack@google.com                fraction += scfx_to_digit(*s, numrep) * scale;
79812854Sgabeblack@google.com            }
79912854Sgabeblack@google.com        }
80012854Sgabeblack@google.com    }
80112854Sgabeblack@google.com
80212854Sgabeblack@google.com    double exp =
80312854Sgabeblack@google.com        (exponent != 0) ? std::pow((double) base, (double) exponent) : 1;
80412854Sgabeblack@google.com
80512854Sgabeblack@google.com    return (sign * (integer + fraction) * exp);
80612854Sgabeblack@google.com}
80712854Sgabeblack@google.com
80812854Sgabeblack@google.com#undef SCFX_FAIL_IF_
80912854Sgabeblack@google.com
81012854Sgabeblack@google.com} // namespace sc_dt
811