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