scfx_rep.cc revision 13322
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  scfx_rep.cpp -
2312854Sgabeblack@google.com
2412854Sgabeblack@google.com  Original Author: Robert Graulich, Synopsys, Inc.
2512854Sgabeblack@google.com                   Martin Janssen,  Synopsys, Inc.
2612854Sgabeblack@google.com
2712854Sgabeblack@google.com *****************************************************************************/
2812854Sgabeblack@google.com
2912854Sgabeblack@google.com/*****************************************************************************
3012854Sgabeblack@google.com
3112854Sgabeblack@google.com  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
3212854Sgabeblack@google.com  changes you are making here.
3312854Sgabeblack@google.com
3412854Sgabeblack@google.com      Name, Affiliation, Date:
3512854Sgabeblack@google.com  Description of Modification:
3612854Sgabeblack@google.com
3712854Sgabeblack@google.com *****************************************************************************/
3812854Sgabeblack@google.com
3912854Sgabeblack@google.com
4012854Sgabeblack@google.com// $Log: scfx_rep.cpp,v $
4112854Sgabeblack@google.com// Revision 1.4  2011/08/24 22:05:43  acg
4212854Sgabeblack@google.com//  Torsten Maehne: initialization changes to remove warnings.
4312854Sgabeblack@google.com//
4412854Sgabeblack@google.com// Revision 1.3  2011/08/15 16:43:24  acg
4512854Sgabeblack@google.com//  Torsten Maehne: changes to remove unused argument warnings.
4612854Sgabeblack@google.com//
4712854Sgabeblack@google.com// Revision 1.2  2009/02/28 00:26:20  acg
4812854Sgabeblack@google.com//  Andy Goodrich: bug fixes.
4912854Sgabeblack@google.com//
5012854Sgabeblack@google.com// Revision 1.2  2008/11/06 17:22:47  acg
5112854Sgabeblack@google.com//  Andy Goodrich: bug fixes for 2.2.1.
5212854Sgabeblack@google.com//
5312854Sgabeblack@google.com// Revision 1.1.1.1  2006/12/15 20:31:36  acg
5412854Sgabeblack@google.com// SystemC 2.2
5512854Sgabeblack@google.com//
5612854Sgabeblack@google.com// Revision 1.3  2006/01/13 18:53:58  acg
5712854Sgabeblack@google.com// Andy Goodrich: added $Log command so that CVS comments are reproduced in
5812854Sgabeblack@google.com// the source.
5912854Sgabeblack@google.com//
6012854Sgabeblack@google.com
6112854Sgabeblack@google.com#include <cctype>
6212854Sgabeblack@google.com#include <cmath>
6312854Sgabeblack@google.com#include <cstdio>
6412854Sgabeblack@google.com#include <cstdlib>
6512854Sgabeblack@google.com
6612854Sgabeblack@google.com#include "base/compiler.hh"
6712854Sgabeblack@google.com#include "systemc/ext/dt/bit/sc_bv_base.hh"
6812854Sgabeblack@google.com#include "systemc/ext/dt/bit/sc_lv_base.hh"
6912854Sgabeblack@google.com#include "systemc/ext/dt/fx/scfx_ieee.hh"
7012854Sgabeblack@google.com#include "systemc/ext/dt/fx/scfx_pow10.hh"
7112854Sgabeblack@google.com#include "systemc/ext/dt/fx/scfx_rep.hh"
7212854Sgabeblack@google.com#include "systemc/ext/dt/fx/scfx_utils.hh"
7312854Sgabeblack@google.com#include "systemc/ext/utils/endian.hh"
7413322Sgabeblack@google.com#include "systemc/ext/utils/messages.hh"
7512854Sgabeblack@google.com
7612854Sgabeblack@google.comnamespace sc_dt
7712854Sgabeblack@google.com{
7812854Sgabeblack@google.com
7912854Sgabeblack@google.com// ----------------------------------------------------------------------------
8012854Sgabeblack@google.com//  some utilities
8112854Sgabeblack@google.com// ----------------------------------------------------------------------------
8212854Sgabeblack@google.com
8312854Sgabeblack@google.comstatic scfx_pow10 pow10_fx;
8412854Sgabeblack@google.com
8512854Sgabeblack@google.comstatic const int mantissa0_size = SCFX_IEEE_DOUBLE_M_SIZE - bits_in_int;
8612854Sgabeblack@google.com
8712854Sgabeblack@google.comstatic inline int
8812854Sgabeblack@google.comn_word(int x)
8912854Sgabeblack@google.com{
9012854Sgabeblack@google.com    return (x + bits_in_word - 1) / bits_in_word;
9112854Sgabeblack@google.com}
9212854Sgabeblack@google.com
9312854Sgabeblack@google.com
9412854Sgabeblack@google.com// ----------------------------------------------------------------------------
9512854Sgabeblack@google.com//  CONSTRUCTORS
9612854Sgabeblack@google.com// ----------------------------------------------------------------------------
9712854Sgabeblack@google.com
9812854Sgabeblack@google.comscfx_rep::scfx_rep() :
9912854Sgabeblack@google.com    m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
10012854Sgabeblack@google.com    m_r_flag(false)
10112854Sgabeblack@google.com{
10212854Sgabeblack@google.com    set_zero();
10312854Sgabeblack@google.com}
10412854Sgabeblack@google.com
10512854Sgabeblack@google.comscfx_rep::scfx_rep(int a) : m_mant(min_mant), m_wp(), m_sign(), m_state(),
10612854Sgabeblack@google.com    m_msw(), m_lsw(), m_r_flag(false)
10712854Sgabeblack@google.com{
10812854Sgabeblack@google.com    if (a != 0) {
10912854Sgabeblack@google.com        m_mant.clear();
11012854Sgabeblack@google.com        m_wp = m_msw = m_lsw = 2;
11112854Sgabeblack@google.com        m_state = normal;
11212854Sgabeblack@google.com        if (a > 0) {
11312854Sgabeblack@google.com            m_mant[2] = a;
11412854Sgabeblack@google.com            m_sign = 1;
11512854Sgabeblack@google.com        } else {
11612854Sgabeblack@google.com            m_mant[2] = -a;
11712854Sgabeblack@google.com            m_sign = -1;
11812854Sgabeblack@google.com        }
11912854Sgabeblack@google.com    } else {
12012854Sgabeblack@google.com        set_zero();
12112854Sgabeblack@google.com    }
12212854Sgabeblack@google.com}
12312854Sgabeblack@google.com
12412854Sgabeblack@google.comscfx_rep::scfx_rep(unsigned int a) : m_mant(min_mant), m_wp(), m_sign(),
12512854Sgabeblack@google.com    m_state(), m_msw(), m_lsw(), m_r_flag(false)
12612854Sgabeblack@google.com{
12712854Sgabeblack@google.com    if (a != 0) {
12812854Sgabeblack@google.com        m_mant.clear();
12912854Sgabeblack@google.com        m_wp = m_msw = m_lsw = 2;
13012854Sgabeblack@google.com        m_state = normal;
13112854Sgabeblack@google.com        m_mant[2] = a;
13212854Sgabeblack@google.com        m_sign = 1;
13312854Sgabeblack@google.com    } else {
13412854Sgabeblack@google.com        set_zero();
13512854Sgabeblack@google.com    }
13612854Sgabeblack@google.com}
13712854Sgabeblack@google.com
13812854Sgabeblack@google.comscfx_rep::scfx_rep(long a) :
13912854Sgabeblack@google.com    m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
14012854Sgabeblack@google.com    m_r_flag(false)
14112854Sgabeblack@google.com{
14212854Sgabeblack@google.com    if (a != 0) {
14312854Sgabeblack@google.com        m_mant.clear();
14412854Sgabeblack@google.com        m_state = normal;
14512854Sgabeblack@google.com        if (a > 0) {
14612854Sgabeblack@google.com            m_sign = 1;
14712854Sgabeblack@google.com        } else {
14812854Sgabeblack@google.com            a = -a;
14912854Sgabeblack@google.com            m_sign = -1;
15012854Sgabeblack@google.com        }
15113197Sgabeblack@google.com#       if SC_LONG_64
15212854Sgabeblack@google.com            m_wp = 1;
15312854Sgabeblack@google.com            m_mant[1] = static_cast<word>(a);
15412854Sgabeblack@google.com            m_mant[2] = static_cast<word>(a >> bits_in_word);
15512854Sgabeblack@google.com            find_sw();
15612854Sgabeblack@google.com#       else
15712854Sgabeblack@google.com            m_wp = 2;
15812854Sgabeblack@google.com            m_msw = 2;
15912854Sgabeblack@google.com            m_lsw = 2;
16012854Sgabeblack@google.com            m_mant[2] = a;
16112854Sgabeblack@google.com#       endif
16212854Sgabeblack@google.com    } else {
16312854Sgabeblack@google.com        set_zero();
16412854Sgabeblack@google.com    }
16512854Sgabeblack@google.com}
16612854Sgabeblack@google.com
16712854Sgabeblack@google.comscfx_rep::scfx_rep(unsigned long a) :
16812854Sgabeblack@google.com    m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
16912854Sgabeblack@google.com    m_r_flag(false)
17012854Sgabeblack@google.com{
17112854Sgabeblack@google.com    if (a != 0) {
17212854Sgabeblack@google.com        m_mant.clear();
17312854Sgabeblack@google.com        m_wp = m_msw = m_lsw = 2;
17412854Sgabeblack@google.com        m_state = normal;
17513197Sgabeblack@google.com#       if SC_LONG_64
17612854Sgabeblack@google.com            m_wp = 1;
17712854Sgabeblack@google.com            m_mant[1] = static_cast<word>(a);
17812854Sgabeblack@google.com            m_mant[2] = static_cast<word>(a >> bits_in_word);
17912854Sgabeblack@google.com            find_sw();
18012854Sgabeblack@google.com#       else
18112854Sgabeblack@google.com            m_wp = 2;
18212854Sgabeblack@google.com            m_msw = 2;
18312854Sgabeblack@google.com            m_lsw = 2;
18412854Sgabeblack@google.com            m_mant[2] = a;
18512854Sgabeblack@google.com#       endif
18612854Sgabeblack@google.com        m_sign = 1;
18712854Sgabeblack@google.com    }
18812854Sgabeblack@google.com    else
18912854Sgabeblack@google.com        set_zero();
19012854Sgabeblack@google.com}
19112854Sgabeblack@google.com
19212854Sgabeblack@google.comscfx_rep::scfx_rep(double a) :
19312854Sgabeblack@google.com    m_mant(min_mant), m_wp(0), m_sign(), m_state(normal), m_msw(0),
19412854Sgabeblack@google.com    m_lsw(0), m_r_flag(false)
19512854Sgabeblack@google.com{
19612854Sgabeblack@google.com    m_mant.clear();
19712854Sgabeblack@google.com
19812854Sgabeblack@google.com    scfx_ieee_double id(a);
19912854Sgabeblack@google.com
20012854Sgabeblack@google.com    m_sign = id.negative() ? -1 : 1;
20112854Sgabeblack@google.com
20212854Sgabeblack@google.com    if (id.is_nan()) {
20312854Sgabeblack@google.com        m_state = not_a_number;
20412854Sgabeblack@google.com    } else if (id.is_inf()) {
20512854Sgabeblack@google.com        m_state = infinity;
20612854Sgabeblack@google.com    } else if (id.is_subnormal()) {
20712854Sgabeblack@google.com        m_mant[0] = id.mantissa1();
20812854Sgabeblack@google.com        m_mant[1] = id.mantissa0();
20912854Sgabeblack@google.com        normalize(id.exponent() + 1 - SCFX_IEEE_DOUBLE_M_SIZE);
21012854Sgabeblack@google.com    } else if (id.is_normal()) {
21112854Sgabeblack@google.com        m_mant[0] = id.mantissa1();
21212854Sgabeblack@google.com        m_mant[1] = id.mantissa0() | (1 << mantissa0_size);
21312854Sgabeblack@google.com        normalize(id.exponent() - SCFX_IEEE_DOUBLE_M_SIZE);
21412854Sgabeblack@google.com    }
21512854Sgabeblack@google.com}
21612854Sgabeblack@google.com
21712854Sgabeblack@google.comscfx_rep::scfx_rep(int64 a) :
21812854Sgabeblack@google.com    m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
21912854Sgabeblack@google.com    m_r_flag(false)
22012854Sgabeblack@google.com{
22112854Sgabeblack@google.com    if (a != 0) {
22212854Sgabeblack@google.com        m_mant.clear();
22312854Sgabeblack@google.com        m_wp = 1;
22412854Sgabeblack@google.com        m_state = normal;
22512854Sgabeblack@google.com        if (a > 0) {
22612854Sgabeblack@google.com            m_mant[1] = static_cast<word>(a);
22712854Sgabeblack@google.com            m_mant[2] = static_cast<word>(a >> bits_in_word);
22812854Sgabeblack@google.com            m_sign = 1;
22912854Sgabeblack@google.com        } else {
23012854Sgabeblack@google.com            m_mant[1] = static_cast<word>(-a);
23112854Sgabeblack@google.com            m_mant[2] = static_cast<word>((-a) >> bits_in_word);
23212854Sgabeblack@google.com            m_sign = -1;
23312854Sgabeblack@google.com        }
23412854Sgabeblack@google.com        find_sw();
23512854Sgabeblack@google.com    } else {
23612854Sgabeblack@google.com        set_zero();
23712854Sgabeblack@google.com    }
23812854Sgabeblack@google.com}
23912854Sgabeblack@google.com
24012854Sgabeblack@google.comscfx_rep::scfx_rep(uint64 a) :
24112854Sgabeblack@google.com    m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
24212854Sgabeblack@google.com    m_r_flag(false)
24312854Sgabeblack@google.com{
24412854Sgabeblack@google.com    if (a != 0) {
24512854Sgabeblack@google.com        m_mant.clear();
24612854Sgabeblack@google.com        m_wp = 1;
24712854Sgabeblack@google.com        m_state = normal;
24812854Sgabeblack@google.com        m_mant[1] = static_cast<word>(a);
24912854Sgabeblack@google.com        m_mant[2] = static_cast<word>(a >> bits_in_word);
25012854Sgabeblack@google.com        m_sign = 1;
25112854Sgabeblack@google.com        find_sw();
25212854Sgabeblack@google.com    } else {
25312854Sgabeblack@google.com        set_zero();
25412854Sgabeblack@google.com    }
25512854Sgabeblack@google.com}
25612854Sgabeblack@google.com
25712854Sgabeblack@google.comscfx_rep::scfx_rep(const sc_signed &a) :
25812854Sgabeblack@google.com    m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
25912854Sgabeblack@google.com    m_r_flag(false)
26012854Sgabeblack@google.com{
26112854Sgabeblack@google.com    if (a.iszero()) {
26212854Sgabeblack@google.com        set_zero();
26312854Sgabeblack@google.com    } else {
26412854Sgabeblack@google.com        int words = n_word(a.length());
26512854Sgabeblack@google.com        if (words > size())
26612854Sgabeblack@google.com            resize_to(words);
26712854Sgabeblack@google.com        m_mant.clear();
26812854Sgabeblack@google.com        m_wp = 0;
26912854Sgabeblack@google.com        m_state = normal;
27012854Sgabeblack@google.com        if (a.sign()) {
27112854Sgabeblack@google.com            sc_signed a2 = -a;
27212854Sgabeblack@google.com            for (int i = 0; i < a2.length(); ++i) {
27312854Sgabeblack@google.com                if (a2[i]) {
27412854Sgabeblack@google.com                    scfx_index x = calc_indices(i);
27512854Sgabeblack@google.com                    m_mant[x.wi()] |= 1 << x.bi();
27612854Sgabeblack@google.com                }
27712854Sgabeblack@google.com            }
27812854Sgabeblack@google.com            m_sign = -1;
27912854Sgabeblack@google.com        } else {
28012854Sgabeblack@google.com            for (int i = 0; i < a.length(); ++i) {
28112854Sgabeblack@google.com                if (a[i]) {
28212854Sgabeblack@google.com                    scfx_index x = calc_indices(i);
28312854Sgabeblack@google.com                    m_mant[x.wi()] |= 1 << x.bi();
28412854Sgabeblack@google.com                }
28512854Sgabeblack@google.com            }
28612854Sgabeblack@google.com            m_sign = 1;
28712854Sgabeblack@google.com        }
28812854Sgabeblack@google.com        find_sw();
28912854Sgabeblack@google.com    }
29012854Sgabeblack@google.com}
29112854Sgabeblack@google.com
29212854Sgabeblack@google.comscfx_rep::scfx_rep(const sc_unsigned &a) :
29312854Sgabeblack@google.com    m_mant(min_mant), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
29412854Sgabeblack@google.com    m_r_flag(false)
29512854Sgabeblack@google.com{
29612854Sgabeblack@google.com    if (a.iszero()) {
29712854Sgabeblack@google.com        set_zero();
29812854Sgabeblack@google.com    } else {
29912854Sgabeblack@google.com        int words = n_word(a.length());
30012854Sgabeblack@google.com        if (words > size())
30112854Sgabeblack@google.com            resize_to(words);
30212854Sgabeblack@google.com        m_mant.clear();
30312854Sgabeblack@google.com        m_wp = 0;
30412854Sgabeblack@google.com        m_state = normal;
30512854Sgabeblack@google.com        for (int i = 0; i < a.length(); ++i) {
30612854Sgabeblack@google.com            if (a[i]) {
30712854Sgabeblack@google.com                scfx_index x = calc_indices(i);
30812854Sgabeblack@google.com                m_mant[x.wi()] |= 1 << x.bi();
30912854Sgabeblack@google.com            }
31012854Sgabeblack@google.com        }
31112854Sgabeblack@google.com        m_sign = 1;
31212854Sgabeblack@google.com        find_sw();
31312854Sgabeblack@google.com    }
31412854Sgabeblack@google.com}
31512854Sgabeblack@google.com
31612854Sgabeblack@google.com// copy constructor
31712854Sgabeblack@google.comscfx_rep::scfx_rep(const scfx_rep &a) :
31812854Sgabeblack@google.com    m_mant(a.m_mant), m_wp(a.m_wp), m_sign(a.m_sign), m_state(a.m_state),
31912854Sgabeblack@google.com    m_msw(a.m_msw), m_lsw(a.m_lsw), m_r_flag(false)
32012854Sgabeblack@google.com{}
32112854Sgabeblack@google.com
32212854Sgabeblack@google.com
32312854Sgabeblack@google.com// ----------------------------------------------------------------------------
32412854Sgabeblack@google.com//  OPERATORS : new, delete
32512854Sgabeblack@google.com//
32612854Sgabeblack@google.com//  Memory management for class scfx_rep.
32712854Sgabeblack@google.com// ----------------------------------------------------------------------------
32812854Sgabeblack@google.com
32912854Sgabeblack@google.comunion scfx_rep_node
33012854Sgabeblack@google.com{
33112854Sgabeblack@google.com    char data[sizeof(scfx_rep)];
33212854Sgabeblack@google.com    scfx_rep_node *next;
33312854Sgabeblack@google.com};
33412854Sgabeblack@google.com
33512854Sgabeblack@google.comstatic scfx_rep_node *list = 0;
33612854Sgabeblack@google.com
33712854Sgabeblack@google.comvoid *
33812854Sgabeblack@google.comscfx_rep::operator new(std::size_t size)
33912854Sgabeblack@google.com{
34012854Sgabeblack@google.com    const int ALLOC_SIZE = 1024;
34112854Sgabeblack@google.com
34212854Sgabeblack@google.com    if (size != sizeof(scfx_rep))
34312854Sgabeblack@google.com        return ::operator new(size);
34412854Sgabeblack@google.com
34512854Sgabeblack@google.com    if (!list) {
34612854Sgabeblack@google.com        list = new scfx_rep_node[ALLOC_SIZE];
34712854Sgabeblack@google.com        for (int i = 0; i < ALLOC_SIZE - 1; i++)
34812854Sgabeblack@google.com            list[i].next = list + i + 1;
34912854Sgabeblack@google.com        list[ALLOC_SIZE - 1].next = 0;
35012854Sgabeblack@google.com    }
35112854Sgabeblack@google.com
35212854Sgabeblack@google.com    scfx_rep *ptr = reinterpret_cast<scfx_rep *>(list->data);
35312854Sgabeblack@google.com    list = list->next;
35412854Sgabeblack@google.com
35512854Sgabeblack@google.com    return ptr;
35612854Sgabeblack@google.com}
35712854Sgabeblack@google.com
35812854Sgabeblack@google.comvoid
35912854Sgabeblack@google.comscfx_rep::operator delete(void *ptr, std::size_t size)
36012854Sgabeblack@google.com{
36112854Sgabeblack@google.com    if (size != sizeof(scfx_rep)) {
36212854Sgabeblack@google.com        ::operator delete(ptr);
36312854Sgabeblack@google.com        return;
36412854Sgabeblack@google.com    }
36512854Sgabeblack@google.com
36612854Sgabeblack@google.com    scfx_rep_node *node = static_cast<scfx_rep_node *>(ptr);
36712854Sgabeblack@google.com    node->next = list;
36812854Sgabeblack@google.com    list = node;
36912854Sgabeblack@google.com}
37012854Sgabeblack@google.com
37112854Sgabeblack@google.com
37212854Sgabeblack@google.com// ----------------------------------------------------------------------------
37312854Sgabeblack@google.com//  METHOD : from_string
37412854Sgabeblack@google.com//
37512854Sgabeblack@google.com//  Convert from character string to sc_fxrep.
37612854Sgabeblack@google.com// ----------------------------------------------------------------------------
37712854Sgabeblack@google.com
37812854Sgabeblack@google.com#define SCFX_FAIL_IF_(cnd) \
37912854Sgabeblack@google.com{ \
38012854Sgabeblack@google.com    if ((cnd)) { \
38112854Sgabeblack@google.com        m_state = not_a_number; \
38212854Sgabeblack@google.com        m_mant.clear(); /* to avoid Purify UMRs during assignment */ \
38312854Sgabeblack@google.com        return; \
38412854Sgabeblack@google.com    } \
38512854Sgabeblack@google.com}
38612854Sgabeblack@google.com
38712854Sgabeblack@google.comvoid
38812854Sgabeblack@google.comscfx_rep::from_string(const char *s, int cte_wl)
38912854Sgabeblack@google.com{
39012854Sgabeblack@google.com    SCFX_FAIL_IF_(s == 0 || *s == 0);
39112854Sgabeblack@google.com
39212854Sgabeblack@google.com    scfx_string s2;
39312854Sgabeblack@google.com    s2 += s;
39412854Sgabeblack@google.com    s2 += '\0';
39512854Sgabeblack@google.com
39612854Sgabeblack@google.com    bool sign_char;
39712854Sgabeblack@google.com    m_sign = scfx_parse_sign(s, sign_char);
39812854Sgabeblack@google.com
39912854Sgabeblack@google.com    sc_numrep numrep = scfx_parse_prefix(s);
40012854Sgabeblack@google.com
40112854Sgabeblack@google.com    int base = 0;
40212854Sgabeblack@google.com
40312854Sgabeblack@google.com    switch (numrep) {
40412854Sgabeblack@google.com      case SC_DEC:
40512854Sgabeblack@google.com        {
40612854Sgabeblack@google.com            base = 10;
40712854Sgabeblack@google.com            if (scfx_is_nan(s)) {   // special case: NaN
40812854Sgabeblack@google.com                m_state = not_a_number;
40912854Sgabeblack@google.com                m_mant.clear(); /* to avoid Purify UMRs during assignment */
41012854Sgabeblack@google.com                return;
41112854Sgabeblack@google.com            }
41212854Sgabeblack@google.com            if (scfx_is_inf(s)) {   // special case: Infinity
41312854Sgabeblack@google.com                m_state = infinity;
41412854Sgabeblack@google.com                m_mant.clear(); /* to avoid Purify UMRs during assignment */
41512854Sgabeblack@google.com                return;
41612854Sgabeblack@google.com            }
41712854Sgabeblack@google.com            break;
41812854Sgabeblack@google.com        }
41912854Sgabeblack@google.com      case SC_BIN:
42012854Sgabeblack@google.com      case SC_BIN_US:
42112854Sgabeblack@google.com        {
42212854Sgabeblack@google.com            SCFX_FAIL_IF_(sign_char);
42312854Sgabeblack@google.com            base = 2;
42412854Sgabeblack@google.com            break;
42512854Sgabeblack@google.com        }
42612854Sgabeblack@google.com
42712854Sgabeblack@google.com      case SC_BIN_SM:
42812854Sgabeblack@google.com        {
42912854Sgabeblack@google.com            base = 2;
43012854Sgabeblack@google.com            break;
43112854Sgabeblack@google.com        }
43212854Sgabeblack@google.com      case SC_OCT:
43312854Sgabeblack@google.com      case SC_OCT_US:
43412854Sgabeblack@google.com        {
43512854Sgabeblack@google.com            SCFX_FAIL_IF_(sign_char);
43612854Sgabeblack@google.com            base = 8;
43712854Sgabeblack@google.com            break;
43812854Sgabeblack@google.com        }
43912854Sgabeblack@google.com      case SC_OCT_SM:
44012854Sgabeblack@google.com        {
44112854Sgabeblack@google.com            base = 8;
44212854Sgabeblack@google.com            break;
44312854Sgabeblack@google.com        }
44412854Sgabeblack@google.com      case SC_HEX:
44512854Sgabeblack@google.com      case SC_HEX_US:
44612854Sgabeblack@google.com        {
44712854Sgabeblack@google.com            SCFX_FAIL_IF_(sign_char);
44812854Sgabeblack@google.com            base = 16;
44912854Sgabeblack@google.com            break;
45012854Sgabeblack@google.com        }
45112854Sgabeblack@google.com      case SC_HEX_SM:
45212854Sgabeblack@google.com        {
45312854Sgabeblack@google.com            base = 16;
45412854Sgabeblack@google.com            break;
45512854Sgabeblack@google.com        }
45612854Sgabeblack@google.com      case SC_CSD:
45712854Sgabeblack@google.com        {
45812854Sgabeblack@google.com            SCFX_FAIL_IF_(sign_char);
45912854Sgabeblack@google.com            base = 2;
46012854Sgabeblack@google.com            scfx_csd2tc(s2);
46112854Sgabeblack@google.com            s = (const char *)s2 + 4;
46212854Sgabeblack@google.com            numrep = SC_BIN;
46312854Sgabeblack@google.com            break;
46412854Sgabeblack@google.com        }
46512854Sgabeblack@google.com      default:
46612854Sgabeblack@google.com        ;
46712854Sgabeblack@google.com    }
46812854Sgabeblack@google.com
46912854Sgabeblack@google.com    //
47012854Sgabeblack@google.com    // find end of mantissa and count the digits and points
47112854Sgabeblack@google.com    //
47212854Sgabeblack@google.com
47312854Sgabeblack@google.com    const char *end = s;
47412854Sgabeblack@google.com    bool based_point = false;
47512854Sgabeblack@google.com    int int_digits = 0;
47612854Sgabeblack@google.com    int frac_digits = 0;
47712854Sgabeblack@google.com
47812854Sgabeblack@google.com    while (*end) {
47912854Sgabeblack@google.com        if (scfx_exp_start(end))
48012854Sgabeblack@google.com            break;
48112854Sgabeblack@google.com
48212854Sgabeblack@google.com        if (*end == '.') {
48312854Sgabeblack@google.com            SCFX_FAIL_IF_(based_point);
48412854Sgabeblack@google.com            based_point = true;
48512854Sgabeblack@google.com        } else {
48612854Sgabeblack@google.com            SCFX_FAIL_IF_(!scfx_is_digit(*end, numrep));
48712854Sgabeblack@google.com            if (based_point)
48812854Sgabeblack@google.com                frac_digits++;
48912854Sgabeblack@google.com            else
49012854Sgabeblack@google.com                int_digits++;
49112854Sgabeblack@google.com        }
49212854Sgabeblack@google.com
49312854Sgabeblack@google.com        ++end;
49412854Sgabeblack@google.com    }
49512854Sgabeblack@google.com
49612854Sgabeblack@google.com    SCFX_FAIL_IF_(int_digits == 0 && frac_digits == 0);
49712854Sgabeblack@google.com
49812854Sgabeblack@google.com    // [ exponent ]
49912854Sgabeblack@google.com    int exponent = 0;
50012854Sgabeblack@google.com
50112854Sgabeblack@google.com    if (*end) {
50212854Sgabeblack@google.com        for (const char *e = end + 2; *e; ++e)
50312854Sgabeblack@google.com            SCFX_FAIL_IF_(!scfx_is_digit(*e, SC_DEC));
50412854Sgabeblack@google.com        exponent = std::atoi(end + 1);
50512854Sgabeblack@google.com    }
50612854Sgabeblack@google.com
50712854Sgabeblack@google.com    //
50812854Sgabeblack@google.com    // check if the mantissa is negative
50912854Sgabeblack@google.com    //
51012854Sgabeblack@google.com    bool mant_is_neg = false;
51112854Sgabeblack@google.com    switch (numrep) {
51212854Sgabeblack@google.com      case SC_BIN:
51312854Sgabeblack@google.com      case SC_OCT:
51412854Sgabeblack@google.com      case SC_HEX:
51512854Sgabeblack@google.com        {
51612854Sgabeblack@google.com            const char *p = s;
51712854Sgabeblack@google.com            if (*p == '.')
51812854Sgabeblack@google.com                ++p;
51912854Sgabeblack@google.com
52012854Sgabeblack@google.com            mant_is_neg = (scfx_to_digit(* p, numrep) >= (base >> 1));
52112854Sgabeblack@google.com            break;
52212854Sgabeblack@google.com        }
52312854Sgabeblack@google.com      default:
52412854Sgabeblack@google.com            ;
52512854Sgabeblack@google.com    }
52612854Sgabeblack@google.com
52712854Sgabeblack@google.com    //
52812854Sgabeblack@google.com    // convert the mantissa
52912854Sgabeblack@google.com    //
53012854Sgabeblack@google.com
53112854Sgabeblack@google.com    switch (base) {
53212854Sgabeblack@google.com      case 2:
53312854Sgabeblack@google.com        {
53412854Sgabeblack@google.com            int bit_offset = exponent % bits_in_word;
53512854Sgabeblack@google.com            int word_offset = exponent / bits_in_word;
53612854Sgabeblack@google.com
53712854Sgabeblack@google.com            int_digits += bit_offset;
53812854Sgabeblack@google.com            frac_digits -= bit_offset;
53912854Sgabeblack@google.com
54012854Sgabeblack@google.com            int words = n_word(int_digits) + n_word(frac_digits);
54112854Sgabeblack@google.com            if (words > size())
54212854Sgabeblack@google.com                resize_to(words);
54312854Sgabeblack@google.com            m_mant.clear();
54412854Sgabeblack@google.com
54512854Sgabeblack@google.com            int j = n_word(frac_digits) * bits_in_word + int_digits - 1;
54612854Sgabeblack@google.com
54712854Sgabeblack@google.com            for (; s < end; s++) {
54812854Sgabeblack@google.com                switch (*s) {
54912854Sgabeblack@google.com                  case '1':
55012854Sgabeblack@google.com                    set_bin(j);
55112854Sgabeblack@google.com                    M5_FALLTHROUGH;
55212854Sgabeblack@google.com                  case '0':
55312854Sgabeblack@google.com                    j--;
55412854Sgabeblack@google.com                    M5_FALLTHROUGH;
55512854Sgabeblack@google.com                  case '.':
55612854Sgabeblack@google.com                    break;
55712854Sgabeblack@google.com                  default:
55812854Sgabeblack@google.com                    SCFX_FAIL_IF_(true); // should not happen
55912854Sgabeblack@google.com                }
56012854Sgabeblack@google.com            }
56112854Sgabeblack@google.com
56212854Sgabeblack@google.com            m_wp = n_word(frac_digits) - word_offset;
56312854Sgabeblack@google.com            break;
56412854Sgabeblack@google.com        }
56512854Sgabeblack@google.com      case 8:
56612854Sgabeblack@google.com        {
56712854Sgabeblack@google.com            exponent *= 3;
56812854Sgabeblack@google.com            int_digits *= 3;
56912854Sgabeblack@google.com            frac_digits *= 3;
57012854Sgabeblack@google.com
57112854Sgabeblack@google.com            int bit_offset = exponent % bits_in_word;
57212854Sgabeblack@google.com            int word_offset = exponent / bits_in_word;
57312854Sgabeblack@google.com
57412854Sgabeblack@google.com            int_digits += bit_offset;
57512854Sgabeblack@google.com            frac_digits -= bit_offset;
57612854Sgabeblack@google.com
57712854Sgabeblack@google.com            int words = n_word(int_digits) + n_word(frac_digits);
57812854Sgabeblack@google.com            if (words > size())
57912854Sgabeblack@google.com                resize_to(words);
58012854Sgabeblack@google.com            m_mant.clear();
58112854Sgabeblack@google.com
58212854Sgabeblack@google.com            int j = n_word(frac_digits) * bits_in_word + int_digits - 3;
58312854Sgabeblack@google.com
58412854Sgabeblack@google.com            for (; s < end; s++) {
58512854Sgabeblack@google.com                switch (*s) {
58612854Sgabeblack@google.com                  case '7': case '6': case '5': case '4':
58712854Sgabeblack@google.com                  case '3': case '2': case '1':
58812854Sgabeblack@google.com                    set_oct(j, *s - '0');
58912854Sgabeblack@google.com                    M5_FALLTHROUGH;
59012854Sgabeblack@google.com                  case '0':
59112854Sgabeblack@google.com                    j -= 3;
59212854Sgabeblack@google.com                    M5_FALLTHROUGH;
59312854Sgabeblack@google.com                  case '.':
59412854Sgabeblack@google.com                    break;
59512854Sgabeblack@google.com                  default:
59612854Sgabeblack@google.com                    SCFX_FAIL_IF_(true); // should not happen
59712854Sgabeblack@google.com                }
59812854Sgabeblack@google.com            }
59912854Sgabeblack@google.com
60012854Sgabeblack@google.com            m_wp = n_word(frac_digits) - word_offset;
60112854Sgabeblack@google.com            break;
60212854Sgabeblack@google.com        }
60312854Sgabeblack@google.com      case 10:
60412854Sgabeblack@google.com        {
60512854Sgabeblack@google.com            word carry, temp;
60612854Sgabeblack@google.com            int length = int_digits + frac_digits;
60712854Sgabeblack@google.com            resize_to(sc_max(min_mant, n_word(4 * length)));
60812854Sgabeblack@google.com
60912854Sgabeblack@google.com            m_mant.clear();
61012854Sgabeblack@google.com            m_msw = m_lsw = 0;
61112854Sgabeblack@google.com
61212854Sgabeblack@google.com            for (; s < end; s++) {
61312854Sgabeblack@google.com                switch (*s) {
61412854Sgabeblack@google.com                  case '9': case '8': case '7': case '6': case '5':
61512854Sgabeblack@google.com                  case '4': case '3': case '2': case '1': case '0':
61612854Sgabeblack@google.com                    multiply_by_ten();
61712854Sgabeblack@google.com                    carry = *s - '0';
61812854Sgabeblack@google.com                    for (int i = 0; carry && i < m_mant.size(); i++) {
61912854Sgabeblack@google.com                        temp = m_mant[i];
62012854Sgabeblack@google.com                        temp += carry;
62112854Sgabeblack@google.com                        carry = temp < m_mant[i];
62212854Sgabeblack@google.com                        m_mant[i] = temp;
62312854Sgabeblack@google.com                    }
62412854Sgabeblack@google.com                  case '.':
62512854Sgabeblack@google.com                    break;
62612854Sgabeblack@google.com                  default:
62712854Sgabeblack@google.com                    SCFX_FAIL_IF_(true); // should not happen
62812854Sgabeblack@google.com                }
62912854Sgabeblack@google.com            }
63012854Sgabeblack@google.com
63112854Sgabeblack@google.com            m_wp = 0;
63212854Sgabeblack@google.com            find_sw();
63312854Sgabeblack@google.com
63412854Sgabeblack@google.com            int denominator = frac_digits - exponent;
63512854Sgabeblack@google.com
63612854Sgabeblack@google.com            if (denominator) {
63712854Sgabeblack@google.com                scfx_rep frac_num = pow10_fx(denominator);
63812854Sgabeblack@google.com                scfx_rep *temp_num =
63912854Sgabeblack@google.com                    div_scfx_rep(const_cast<const scfx_rep &>(*this),
64012854Sgabeblack@google.com                                   frac_num, cte_wl);
64112854Sgabeblack@google.com                *this = *temp_num;
64212854Sgabeblack@google.com                delete temp_num;
64312854Sgabeblack@google.com            }
64412854Sgabeblack@google.com
64512854Sgabeblack@google.com            break;
64612854Sgabeblack@google.com        }
64712854Sgabeblack@google.com      case 16:
64812854Sgabeblack@google.com        {
64912854Sgabeblack@google.com            exponent *= 4;
65012854Sgabeblack@google.com            int_digits *= 4;
65112854Sgabeblack@google.com            frac_digits *= 4;
65212854Sgabeblack@google.com
65312854Sgabeblack@google.com            int bit_offset = exponent % bits_in_word;
65412854Sgabeblack@google.com            int word_offset = exponent / bits_in_word;
65512854Sgabeblack@google.com
65612854Sgabeblack@google.com            int_digits += bit_offset;
65712854Sgabeblack@google.com            frac_digits -= bit_offset;
65812854Sgabeblack@google.com
65912854Sgabeblack@google.com            int words = n_word(int_digits) + n_word(frac_digits);
66012854Sgabeblack@google.com            if (words > size())
66112854Sgabeblack@google.com                resize_to(words);
66212854Sgabeblack@google.com            m_mant.clear();
66312854Sgabeblack@google.com
66412854Sgabeblack@google.com            int j = n_word(frac_digits) * bits_in_word + int_digits - 4;
66512854Sgabeblack@google.com
66612854Sgabeblack@google.com            for (; s < end; s ++) {
66712854Sgabeblack@google.com                switch (*s) {
66812854Sgabeblack@google.com                  case 'f': case 'e': case 'd': case 'c': case 'b': case 'a':
66912854Sgabeblack@google.com                    set_hex(j, *s - 'a' + 10);
67012854Sgabeblack@google.com                    j -= 4;
67112854Sgabeblack@google.com                    break;
67212854Sgabeblack@google.com                  case 'F': case 'E': case 'D': case 'C': case 'B': case 'A':
67312854Sgabeblack@google.com                    set_hex(j, *s - 'A' + 10);
67412854Sgabeblack@google.com                    j -= 4;
67512854Sgabeblack@google.com                    break;
67612854Sgabeblack@google.com                  case '9': case '8': case '7': case '6': case '5':
67712854Sgabeblack@google.com                  case '4': case '3': case '2': case '1':
67812854Sgabeblack@google.com                    set_hex(j, *s - '0');
67912854Sgabeblack@google.com                    M5_FALLTHROUGH;
68012854Sgabeblack@google.com                  case '0':
68112854Sgabeblack@google.com                    j -= 4;
68212854Sgabeblack@google.com                    M5_FALLTHROUGH;
68312854Sgabeblack@google.com                  case '.':
68412854Sgabeblack@google.com                    break;
68512854Sgabeblack@google.com                  default:
68612854Sgabeblack@google.com                    SCFX_FAIL_IF_(true); // should not happen
68712854Sgabeblack@google.com                }
68812854Sgabeblack@google.com            }
68912854Sgabeblack@google.com
69012854Sgabeblack@google.com            m_wp = n_word(frac_digits) - word_offset;
69112854Sgabeblack@google.com            break;
69212854Sgabeblack@google.com        }
69312854Sgabeblack@google.com    }
69412854Sgabeblack@google.com
69512854Sgabeblack@google.com    m_state = normal;
69612854Sgabeblack@google.com    find_sw();
69712854Sgabeblack@google.com
69812854Sgabeblack@google.com    //
69912854Sgabeblack@google.com    // two's complement of mantissa if it is negative
70012854Sgabeblack@google.com    //
70112854Sgabeblack@google.com    if (mant_is_neg) {
70212854Sgabeblack@google.com        m_mant[m_msw] |=  ~0U << scfx_find_msb(m_mant[m_msw]);
70312854Sgabeblack@google.com        for (int i = m_msw + 1; i < m_mant.size(); ++i)
70412854Sgabeblack@google.com            m_mant[i] = static_cast<word>(-1);
70512854Sgabeblack@google.com        complement(m_mant, m_mant, m_mant.size());
70612854Sgabeblack@google.com        inc(m_mant);
70712854Sgabeblack@google.com        m_sign *= -1;
70812854Sgabeblack@google.com        find_sw();
70912854Sgabeblack@google.com    }
71012854Sgabeblack@google.com}
71112854Sgabeblack@google.com
71212854Sgabeblack@google.com#undef SCFX_FAIL_IF_
71312854Sgabeblack@google.com
71412854Sgabeblack@google.com// ----------------------------------------------------------------------------
71512854Sgabeblack@google.com//  METHOD : to_double
71612854Sgabeblack@google.com//
71712854Sgabeblack@google.com//  Convert from scfx_rep to double.
71812854Sgabeblack@google.com// ----------------------------------------------------------------------------
71912854Sgabeblack@google.com
72012854Sgabeblack@google.comdouble
72112854Sgabeblack@google.comscfx_rep::to_double() const
72212854Sgabeblack@google.com{
72312854Sgabeblack@google.com    scfx_ieee_double id;
72412854Sgabeblack@google.com
72512854Sgabeblack@google.com    // handle special cases
72612854Sgabeblack@google.com    if (is_nan()) {
72712854Sgabeblack@google.com        id.set_nan();
72812854Sgabeblack@google.com        return id;
72912854Sgabeblack@google.com    }
73012854Sgabeblack@google.com
73112854Sgabeblack@google.com    if (is_inf()) {
73212854Sgabeblack@google.com        id.set_inf();
73312854Sgabeblack@google.com        id.negative(m_sign < 0);
73412854Sgabeblack@google.com        return id;
73512854Sgabeblack@google.com    }
73612854Sgabeblack@google.com
73712854Sgabeblack@google.com    if (is_zero()) {
73812854Sgabeblack@google.com        id = 0.;
73912854Sgabeblack@google.com        id.negative(m_sign < 0);
74012854Sgabeblack@google.com        return id;
74112854Sgabeblack@google.com    }
74212854Sgabeblack@google.com
74312854Sgabeblack@google.com    int msb = scfx_find_msb(m_mant[m_msw]);
74412854Sgabeblack@google.com
74512854Sgabeblack@google.com    int exp = (m_msw - m_wp) * bits_in_word + msb;
74612854Sgabeblack@google.com
74712854Sgabeblack@google.com    if (exp > SCFX_IEEE_DOUBLE_E_MAX) {
74812854Sgabeblack@google.com        id.set_inf();
74912854Sgabeblack@google.com        id.negative(m_sign < 0);
75012854Sgabeblack@google.com        return id;
75112854Sgabeblack@google.com    }
75212854Sgabeblack@google.com
75312854Sgabeblack@google.com    if (exp < SCFX_IEEE_DOUBLE_E_MIN -
75412854Sgabeblack@google.com        static_cast<int>(SCFX_IEEE_DOUBLE_M_SIZE))
75512854Sgabeblack@google.com    {
75612854Sgabeblack@google.com        id = 0.;
75712854Sgabeblack@google.com        return id;
75812854Sgabeblack@google.com    }
75912854Sgabeblack@google.com
76012854Sgabeblack@google.com    int shift = mantissa0_size - msb;
76112854Sgabeblack@google.com
76212854Sgabeblack@google.com    unsigned int m0;
76312854Sgabeblack@google.com    unsigned int m1 = 0;
76412854Sgabeblack@google.com    unsigned int guard = 0;
76512854Sgabeblack@google.com
76612854Sgabeblack@google.com    if (shift == 0) {
76712854Sgabeblack@google.com        m0 = m_mant[m_msw] & ~(1 << mantissa0_size);
76812854Sgabeblack@google.com        if (m_msw > m_lsw) {
76912854Sgabeblack@google.com            m1 = m_mant[m_msw - 1];
77012854Sgabeblack@google.com            if (m_msw - 1 > m_lsw)
77112854Sgabeblack@google.com                guard = m_mant[m_msw - 2] >> (bits_in_word - 1);
77212854Sgabeblack@google.com        }
77312854Sgabeblack@google.com    } else if (shift < 0) {
77412854Sgabeblack@google.com        m0 = (m_mant[m_msw] >> -shift) & ~(1 << mantissa0_size);
77512854Sgabeblack@google.com        m1 = m_mant[m_msw] << (bits_in_word + shift);
77612854Sgabeblack@google.com        if (m_msw > m_lsw) {
77712854Sgabeblack@google.com            m1 |= m_mant[m_msw - 1] >> -shift;
77812854Sgabeblack@google.com            guard = (m_mant[m_msw - 1] >> (-shift - 1)) & 1;
77912854Sgabeblack@google.com        }
78012854Sgabeblack@google.com    } else {
78112854Sgabeblack@google.com        m0 = (m_mant[m_msw] << shift) & ~(1 << mantissa0_size);
78212854Sgabeblack@google.com        if (m_msw > m_lsw) {
78312854Sgabeblack@google.com            m0 |= m_mant[m_msw - 1] >> (bits_in_word - shift);
78412854Sgabeblack@google.com            m1 = m_mant[m_msw - 1] << shift;
78512854Sgabeblack@google.com            if (m_msw - 1 > m_lsw) {
78612854Sgabeblack@google.com                m1 |= m_mant[m_msw - 2] >> (bits_in_word - shift);
78712854Sgabeblack@google.com                guard = (m_mant[m_msw - 2] >> (bits_in_word - shift - 1)) & 1;
78812854Sgabeblack@google.com            }
78912854Sgabeblack@google.com        }
79012854Sgabeblack@google.com    }
79112854Sgabeblack@google.com
79212854Sgabeblack@google.com    if (exp < SCFX_IEEE_DOUBLE_E_MIN) {
79312854Sgabeblack@google.com        m0 |= (1 << mantissa0_size);
79412854Sgabeblack@google.com
79512854Sgabeblack@google.com        int subnormal_shift = SCFX_IEEE_DOUBLE_E_MIN - exp;
79612854Sgabeblack@google.com
79712854Sgabeblack@google.com        if (subnormal_shift < bits_in_word) {
79812854Sgabeblack@google.com            m1 = m1 >> subnormal_shift |
79912854Sgabeblack@google.com                m0 << (bits_in_word - subnormal_shift);
80012854Sgabeblack@google.com            m0 = m0 >> subnormal_shift;
80112854Sgabeblack@google.com        } else {
80212854Sgabeblack@google.com            m1 = m0 >> (subnormal_shift - bits_in_word);
80312854Sgabeblack@google.com            m0 = 0;
80412854Sgabeblack@google.com        }
80512854Sgabeblack@google.com
80612854Sgabeblack@google.com        guard = 0;
80712854Sgabeblack@google.com
80812854Sgabeblack@google.com        exp = SCFX_IEEE_DOUBLE_E_MIN - 1;
80912854Sgabeblack@google.com    }
81012854Sgabeblack@google.com
81112854Sgabeblack@google.com    id.mantissa0(m0);
81212854Sgabeblack@google.com    id.mantissa1(m1);
81312854Sgabeblack@google.com    id.exponent(exp);
81412854Sgabeblack@google.com    id.negative(m_sign < 0);
81512854Sgabeblack@google.com
81612854Sgabeblack@google.com    double result = id;
81712854Sgabeblack@google.com
81812854Sgabeblack@google.com    if (guard != 0)
81912854Sgabeblack@google.com        result += m_sign * scfx_pow2(exp - SCFX_IEEE_DOUBLE_M_SIZE);
82012854Sgabeblack@google.com
82112854Sgabeblack@google.com    return result;
82212854Sgabeblack@google.com}
82312854Sgabeblack@google.com
82412854Sgabeblack@google.com
82512854Sgabeblack@google.com// ----------------------------------------------------------------------------
82612854Sgabeblack@google.com//  METHOD : to_uint64
82712854Sgabeblack@google.com//
82812854Sgabeblack@google.com//  Convert from scfx_rep to uint64.
82912854Sgabeblack@google.com//  Truncates towards 0 _then_ wraps; infinities and NaN go to zero.
83012854Sgabeblack@google.com// ----------------------------------------------------------------------------
83112854Sgabeblack@google.com
83212854Sgabeblack@google.comuint64
83312854Sgabeblack@google.comscfx_rep::to_uint64() const
83412854Sgabeblack@google.com{
83512854Sgabeblack@google.com    if (!is_normal() || is_zero()) {
83612854Sgabeblack@google.com        return 0;
83712854Sgabeblack@google.com    }
83812854Sgabeblack@google.com
83912854Sgabeblack@google.com    uint64 result = 0;
84012854Sgabeblack@google.com    int shift = 0;
84112854Sgabeblack@google.com    int idx = m_wp;
84212854Sgabeblack@google.com
84312854Sgabeblack@google.com    // Ignore bits off the top; they modulo out.
84412854Sgabeblack@google.com    // Ignore bits off the bottom; we're truncating.
84512854Sgabeblack@google.com    while (shift < 64 && m_msw >= idx && idx >= m_lsw) {
84612854Sgabeblack@google.com        result += static_cast<uint64>(m_mant[idx]) << shift;
84712854Sgabeblack@google.com        shift += bits_in_word;
84812854Sgabeblack@google.com        idx += 1;
84912854Sgabeblack@google.com    }
85012854Sgabeblack@google.com
85112854Sgabeblack@google.com    return m_sign > 0 ? result : -result;
85212854Sgabeblack@google.com}
85312854Sgabeblack@google.com
85412854Sgabeblack@google.com
85512854Sgabeblack@google.com// ----------------------------------------------------------------------------
85612854Sgabeblack@google.com//  METHOD : to_string
85712854Sgabeblack@google.com//
85812854Sgabeblack@google.com//  Convert from scfx_rep to character string.
85912854Sgabeblack@google.com// ----------------------------------------------------------------------------
86012854Sgabeblack@google.com
86112854Sgabeblack@google.comvoid
86212854Sgabeblack@google.comprint_dec(scfx_string &s, const scfx_rep &num, int w_prefix, sc_fmt fmt)
86312854Sgabeblack@google.com{
86412854Sgabeblack@google.com    if (num.is_neg())
86512854Sgabeblack@google.com        s += '-';
86612854Sgabeblack@google.com
86712854Sgabeblack@google.com    if (w_prefix == 1) {
86812854Sgabeblack@google.com        scfx_print_prefix(s, SC_DEC);
86912854Sgabeblack@google.com    }
87012854Sgabeblack@google.com
87112854Sgabeblack@google.com    if (num.is_zero()) {
87212854Sgabeblack@google.com        s += '0';
87312854Sgabeblack@google.com        return;
87412854Sgabeblack@google.com    }
87512854Sgabeblack@google.com
87612854Sgabeblack@google.com    // split 'num' into its integer and fractional part
87712854Sgabeblack@google.com    scfx_rep int_part = num;
87812854Sgabeblack@google.com    scfx_rep frac_part = num;
87912854Sgabeblack@google.com
88012854Sgabeblack@google.com    int i;
88112854Sgabeblack@google.com
88212854Sgabeblack@google.com    for (i = int_part.m_lsw; i <= int_part.m_msw && i < int_part.m_wp; i++)
88312854Sgabeblack@google.com        int_part.m_mant[i] = 0;
88412854Sgabeblack@google.com    int_part.find_sw();
88512854Sgabeblack@google.com    if (int_part.m_wp < int_part.m_lsw)
88612854Sgabeblack@google.com        int_part.resize_to(int_part.size() - int_part.m_wp, -1);
88712854Sgabeblack@google.com
88812854Sgabeblack@google.com    for (i = frac_part.m_msw;
88912854Sgabeblack@google.com            i >= frac_part.m_lsw && i >= frac_part.m_wp; i--)
89012854Sgabeblack@google.com        frac_part.m_mant[i] = 0;
89112854Sgabeblack@google.com    frac_part.find_sw();
89212854Sgabeblack@google.com    if (frac_part.m_msw == frac_part.size() - 1)
89312854Sgabeblack@google.com        frac_part.resize_to(frac_part.size() + 1, 1);
89412854Sgabeblack@google.com
89512854Sgabeblack@google.com    // print integer part
89612854Sgabeblack@google.com    int int_digits = 0;
89712854Sgabeblack@google.com    int int_zeros  = 0;
89812854Sgabeblack@google.com
89912854Sgabeblack@google.com    if (!int_part.is_zero()) {
90012854Sgabeblack@google.com        double int_wl = (int_part.m_msw - int_part.m_wp) * bits_in_word +
90112854Sgabeblack@google.com                         scfx_find_msb(int_part.m_mant[int_part.m_msw]) + 1;
90212854Sgabeblack@google.com        int_digits = (int)std::ceil(int_wl * std::log10(2.));
90312854Sgabeblack@google.com
90412854Sgabeblack@google.com        int len = s.length();
90512854Sgabeblack@google.com        s.append(int_digits);
90612854Sgabeblack@google.com
90712854Sgabeblack@google.com        bool zero_digits = (frac_part.is_zero() && fmt != SC_F);
90812854Sgabeblack@google.com
90912854Sgabeblack@google.com        for (i = int_digits + len - 1; i >= len; i--) {
91012854Sgabeblack@google.com            unsigned int remainder = int_part.divide_by_ten();
91112854Sgabeblack@google.com            s[i] = static_cast<char>('0' + remainder);
91212854Sgabeblack@google.com
91312854Sgabeblack@google.com            if (zero_digits) {
91412854Sgabeblack@google.com                if (remainder == 0)
91512854Sgabeblack@google.com                    int_zeros++;
91612854Sgabeblack@google.com                else
91712854Sgabeblack@google.com                    zero_digits = false;
91812854Sgabeblack@google.com            }
91912854Sgabeblack@google.com        }
92012854Sgabeblack@google.com
92112854Sgabeblack@google.com        // discard trailing zeros from int_part
92212854Sgabeblack@google.com        s.discard(int_zeros);
92312854Sgabeblack@google.com
92412854Sgabeblack@google.com        if (s[len] == '0') {
92512854Sgabeblack@google.com            // int_digits was overestimated by one
92612854Sgabeblack@google.com            s.remove(len);
92712854Sgabeblack@google.com            --int_digits;
92812854Sgabeblack@google.com        }
92912854Sgabeblack@google.com    }
93012854Sgabeblack@google.com
93112854Sgabeblack@google.com    // print fractional part
93212854Sgabeblack@google.com    int frac_digits = 0;
93312854Sgabeblack@google.com    int frac_zeros  = 0;
93412854Sgabeblack@google.com
93512854Sgabeblack@google.com    if (!frac_part.is_zero()) {
93612854Sgabeblack@google.com        s += '.';
93712854Sgabeblack@google.com
93812854Sgabeblack@google.com        bool zero_digits = (int_digits == 0 && fmt != SC_F);
93912854Sgabeblack@google.com
94012854Sgabeblack@google.com        double frac_wl = (frac_part.m_wp - frac_part.m_msw) * bits_in_word -
94112854Sgabeblack@google.com                          scfx_find_msb(frac_part.m_mant[frac_part.m_msw]) - 1;
94212854Sgabeblack@google.com        frac_zeros = (int)std::floor(frac_wl * std::log10(2.));
94312854Sgabeblack@google.com
94412854Sgabeblack@google.com        scfx_rep temp;
94512854Sgabeblack@google.com        sc_dt::multiply(temp, frac_part, pow10_fx(frac_zeros));
94612854Sgabeblack@google.com        frac_part = temp;
94712854Sgabeblack@google.com        if (frac_part.m_msw == frac_part.size() - 1)
94812854Sgabeblack@google.com            frac_part.resize_to(frac_part.size() + 1, 1);
94912854Sgabeblack@google.com
95012854Sgabeblack@google.com        frac_digits = frac_zeros;
95112854Sgabeblack@google.com        if (!zero_digits) {
95212854Sgabeblack@google.com            for (i = 0; i < frac_zeros; i++)
95312854Sgabeblack@google.com                s += '0';
95412854Sgabeblack@google.com            frac_zeros = 0;
95512854Sgabeblack@google.com        }
95612854Sgabeblack@google.com
95712854Sgabeblack@google.com        while (!frac_part.is_zero()) {
95812854Sgabeblack@google.com            frac_part.multiply_by_ten();
95912854Sgabeblack@google.com            int n = frac_part.m_mant[frac_part.m_msw + 1];
96012854Sgabeblack@google.com
96112854Sgabeblack@google.com            if (zero_digits) {
96212854Sgabeblack@google.com                if (n == 0)
96312854Sgabeblack@google.com                    frac_zeros++;
96412854Sgabeblack@google.com                else
96512854Sgabeblack@google.com                    zero_digits = false;
96612854Sgabeblack@google.com            }
96712854Sgabeblack@google.com
96812854Sgabeblack@google.com            if (! zero_digits)
96912854Sgabeblack@google.com                s += static_cast<char>('0' + n);
97012854Sgabeblack@google.com
97112854Sgabeblack@google.com            frac_part.m_mant[frac_part.m_msw + 1] = 0;
97212854Sgabeblack@google.com            frac_digits++;
97312854Sgabeblack@google.com        }
97412854Sgabeblack@google.com    }
97512854Sgabeblack@google.com
97612854Sgabeblack@google.com    // print exponent
97712854Sgabeblack@google.com    if (fmt != SC_F) {
97812854Sgabeblack@google.com        if (frac_digits == 0)
97912854Sgabeblack@google.com            scfx_print_exp(s, int_zeros);
98012854Sgabeblack@google.com        else if (int_digits == 0)
98112854Sgabeblack@google.com            scfx_print_exp(s, -frac_zeros);
98212854Sgabeblack@google.com    }
98312854Sgabeblack@google.com}
98412854Sgabeblack@google.com
98512854Sgabeblack@google.comvoid
98612854Sgabeblack@google.comprint_other(scfx_string &s, const scfx_rep &a, sc_numrep numrep, int w_prefix,
98712854Sgabeblack@google.com            sc_fmt fmt, const scfx_params *params)
98812854Sgabeblack@google.com{
98912854Sgabeblack@google.com    scfx_rep b = a;
99012854Sgabeblack@google.com
99112854Sgabeblack@google.com    sc_numrep numrep2 = numrep;
99212854Sgabeblack@google.com
99312854Sgabeblack@google.com    bool numrep_is_sm = (numrep == SC_BIN_SM ||
99412854Sgabeblack@google.com                         numrep == SC_OCT_SM ||
99512854Sgabeblack@google.com                         numrep == SC_HEX_SM);
99612854Sgabeblack@google.com
99712854Sgabeblack@google.com    if (numrep_is_sm) {
99812854Sgabeblack@google.com        if (b.is_neg()) {
99912854Sgabeblack@google.com            s += '-';
100012854Sgabeblack@google.com            b = *neg_scfx_rep(a);
100112854Sgabeblack@google.com        }
100212854Sgabeblack@google.com        switch (numrep) {
100312854Sgabeblack@google.com          case SC_BIN_SM:
100412854Sgabeblack@google.com            numrep2 = SC_BIN_US;
100512854Sgabeblack@google.com            break;
100612854Sgabeblack@google.com          case SC_OCT_SM:
100712854Sgabeblack@google.com            numrep2 = SC_OCT_US;
100812854Sgabeblack@google.com            break;
100912854Sgabeblack@google.com          case SC_HEX_SM:
101012854Sgabeblack@google.com            numrep2 = SC_HEX_US;
101112854Sgabeblack@google.com            break;
101212854Sgabeblack@google.com          default:
101312854Sgabeblack@google.com            ;
101412854Sgabeblack@google.com        }
101512854Sgabeblack@google.com    }
101612854Sgabeblack@google.com
101712854Sgabeblack@google.com    if (w_prefix != 0) {
101812854Sgabeblack@google.com        scfx_print_prefix(s, numrep);
101912854Sgabeblack@google.com    }
102012854Sgabeblack@google.com
102112854Sgabeblack@google.com    numrep = numrep2;
102212854Sgabeblack@google.com
102312854Sgabeblack@google.com    int msb, lsb;
102412854Sgabeblack@google.com
102512854Sgabeblack@google.com    if (params != 0) {
102612854Sgabeblack@google.com        msb = params->iwl() - 1;
102712854Sgabeblack@google.com        lsb = params->iwl() - params->wl();
102812854Sgabeblack@google.com
102912854Sgabeblack@google.com        if (params->enc() == SC_TC_ &&
103012854Sgabeblack@google.com            (numrep == SC_BIN_US ||
103112854Sgabeblack@google.com              numrep == SC_OCT_US ||
103212854Sgabeblack@google.com              numrep == SC_HEX_US) &&
103312854Sgabeblack@google.com            !numrep_is_sm &&
103412854Sgabeblack@google.com            params->wl() > 1) {
103512854Sgabeblack@google.com            --msb;
103612854Sgabeblack@google.com        } else if (params->enc() == SC_US_ &&
103712854Sgabeblack@google.com            (numrep == SC_BIN ||
103812854Sgabeblack@google.com              numrep == SC_OCT ||
103912854Sgabeblack@google.com              numrep == SC_HEX ||
104012854Sgabeblack@google.com              numrep == SC_CSD)) {
104112854Sgabeblack@google.com            ++msb;
104212854Sgabeblack@google.com        }
104312854Sgabeblack@google.com    } else {
104412854Sgabeblack@google.com        if (b.is_zero()) {
104512854Sgabeblack@google.com            msb = 0;
104612854Sgabeblack@google.com            lsb = 0;
104712854Sgabeblack@google.com        } else {
104812854Sgabeblack@google.com            msb = (b.m_msw - b.m_wp) * bits_in_word
104912854Sgabeblack@google.com                + scfx_find_msb(b.m_mant[ b.m_msw ]) + 1;
105012854Sgabeblack@google.com            while (b.get_bit(msb) == b.get_bit(msb - 1))
105112854Sgabeblack@google.com                --msb;
105212854Sgabeblack@google.com
105312854Sgabeblack@google.com            if (numrep == SC_BIN_US ||
105412854Sgabeblack@google.com                numrep == SC_OCT_US ||
105512854Sgabeblack@google.com                numrep == SC_HEX_US) {
105612854Sgabeblack@google.com                --msb;
105712854Sgabeblack@google.com            }
105812854Sgabeblack@google.com
105912854Sgabeblack@google.com            lsb = (b.m_lsw - b.m_wp) * bits_in_word +
106012854Sgabeblack@google.com                scfx_find_lsb(b.m_mant[b.m_lsw]);
106113197Sgabeblack@google.com
106212854Sgabeblack@google.com        }
106312854Sgabeblack@google.com    }
106412854Sgabeblack@google.com
106512854Sgabeblack@google.com    int step;
106612854Sgabeblack@google.com
106712854Sgabeblack@google.com    switch (numrep) {
106812854Sgabeblack@google.com      case SC_BIN:
106912854Sgabeblack@google.com      case SC_BIN_US:
107012854Sgabeblack@google.com      case SC_CSD:
107112854Sgabeblack@google.com        step = 1;
107212854Sgabeblack@google.com       break;
107312854Sgabeblack@google.com      case SC_OCT:
107412854Sgabeblack@google.com      case SC_OCT_US:
107512854Sgabeblack@google.com        step = 3;
107612854Sgabeblack@google.com        break;
107712854Sgabeblack@google.com      case SC_HEX:
107812854Sgabeblack@google.com      case SC_HEX_US:
107912854Sgabeblack@google.com        step = 4;
108012854Sgabeblack@google.com        break;
108112854Sgabeblack@google.com      default:
108213322Sgabeblack@google.com        SC_REPORT_FATAL(sc_core::SC_ID_ASSERTION_FAILED_,
108313322Sgabeblack@google.com                "unexpected sc_numrep");
108412854Sgabeblack@google.com        sc_core::sc_abort();
108512854Sgabeblack@google.com    }
108612854Sgabeblack@google.com
108712854Sgabeblack@google.com    msb = (int)std::ceil(double(msb + 1) / step) * step - 1;
108812854Sgabeblack@google.com
108912854Sgabeblack@google.com    lsb = (int)std::floor(double(lsb) / step) * step;
109012854Sgabeblack@google.com
109112854Sgabeblack@google.com    if (msb < 0) {
109212854Sgabeblack@google.com        s += '.';
109312854Sgabeblack@google.com        if (fmt == SC_F) {
109412854Sgabeblack@google.com            int sign = (b.is_neg()) ? (1 << step) - 1 : 0;
109512854Sgabeblack@google.com            for (int i = (msb + 1) / step; i < 0; i++) {
109612854Sgabeblack@google.com                if (sign < 10)
109712854Sgabeblack@google.com                    s += static_cast<char>(sign + '0');
109812854Sgabeblack@google.com                else
109912854Sgabeblack@google.com                    s += static_cast<char>(sign + 'a' - 10);
110012854Sgabeblack@google.com            }
110112854Sgabeblack@google.com        }
110212854Sgabeblack@google.com    }
110312854Sgabeblack@google.com
110412854Sgabeblack@google.com    int i = msb;
110512854Sgabeblack@google.com    while (i >= lsb) {
110612854Sgabeblack@google.com        int value = 0;
110712854Sgabeblack@google.com        for (int j = step - 1; j >= 0; --j) {
110812854Sgabeblack@google.com            value += static_cast<int>(b.get_bit(i)) << j;
110912854Sgabeblack@google.com            --i;
111012854Sgabeblack@google.com        }
111112854Sgabeblack@google.com        if (value < 10)
111212854Sgabeblack@google.com            s += static_cast<char>(value + '0');
111312854Sgabeblack@google.com        else
111412854Sgabeblack@google.com            s += static_cast<char>(value + 'a' - 10);
111512854Sgabeblack@google.com        if (i == -1)
111612854Sgabeblack@google.com            s += '.';
111712854Sgabeblack@google.com    }
111812854Sgabeblack@google.com
111912854Sgabeblack@google.com    if (lsb > 0 && fmt == SC_F) {
112012854Sgabeblack@google.com        for (int i = lsb / step; i > 0; i--)
112112854Sgabeblack@google.com            s += '0';
112212854Sgabeblack@google.com    }
112312854Sgabeblack@google.com
112412854Sgabeblack@google.com    if (s[s.length() - 1] == '.')
112512854Sgabeblack@google.com        s.discard(1);
112612854Sgabeblack@google.com
112712854Sgabeblack@google.com    if (fmt != SC_F) {
112812854Sgabeblack@google.com        if (msb < 0)
112912854Sgabeblack@google.com            scfx_print_exp(s, (msb + 1) / step);
113012854Sgabeblack@google.com        else if (lsb > 0)
113112854Sgabeblack@google.com            scfx_print_exp(s, lsb / step);
113212854Sgabeblack@google.com    }
113312854Sgabeblack@google.com
113412854Sgabeblack@google.com    if (numrep == SC_CSD)
113512854Sgabeblack@google.com        scfx_tc2csd(s, w_prefix);
113612854Sgabeblack@google.com}
113712854Sgabeblack@google.com
113812854Sgabeblack@google.comconst char *
113912854Sgabeblack@google.comscfx_rep::to_string(sc_numrep numrep, int w_prefix,
114012854Sgabeblack@google.com                    sc_fmt fmt, const scfx_params *params) const
114112854Sgabeblack@google.com{
114212854Sgabeblack@google.com    static scfx_string s;
114312854Sgabeblack@google.com
114412854Sgabeblack@google.com    s.clear();
114512854Sgabeblack@google.com
114612854Sgabeblack@google.com    if (is_nan()) {
114712854Sgabeblack@google.com        scfx_print_nan(s);
114812854Sgabeblack@google.com    } else if (is_inf()) {
114912854Sgabeblack@google.com        scfx_print_inf(s, is_neg());
115012854Sgabeblack@google.com    } else if (is_neg() && !is_zero() &&
115112854Sgabeblack@google.com               (numrep == SC_BIN_US ||
115212854Sgabeblack@google.com                numrep == SC_OCT_US ||
115312854Sgabeblack@google.com                numrep == SC_HEX_US)) {
115412854Sgabeblack@google.com        s += "negative";
115512854Sgabeblack@google.com    } else if (numrep == SC_DEC || numrep == SC_NOBASE) {
115612854Sgabeblack@google.com        sc_dt::print_dec(s, *this, w_prefix, fmt);
115712854Sgabeblack@google.com    } else {
115812854Sgabeblack@google.com        sc_dt::print_other(s, *this, numrep, w_prefix, fmt, params);
115912854Sgabeblack@google.com    }
116012854Sgabeblack@google.com
116112854Sgabeblack@google.com    return s;
116212854Sgabeblack@google.com}
116312854Sgabeblack@google.com
116412854Sgabeblack@google.com
116512854Sgabeblack@google.com// ----------------------------------------------------------------------------
116612854Sgabeblack@google.com//  ADD
116712854Sgabeblack@google.com//
116812854Sgabeblack@google.com//  add two mantissas of the same size
116912854Sgabeblack@google.com//  result has the same size
117012854Sgabeblack@google.com//  returns carry of operation
117112854Sgabeblack@google.com// ----------------------------------------------------------------------------
117212854Sgabeblack@google.com
117312854Sgabeblack@google.comstatic inline int
117412854Sgabeblack@google.comadd_mants(int size, scfx_mant &result, const scfx_mant &a, const scfx_mant &b)
117512854Sgabeblack@google.com{
117612854Sgabeblack@google.com    unsigned int carry = 0;
117712854Sgabeblack@google.com
117812854Sgabeblack@google.com    int index = 0;
117912854Sgabeblack@google.com
118012854Sgabeblack@google.com    do {
118112854Sgabeblack@google.com        word x = a[index];
118212854Sgabeblack@google.com        word y = b[index];
118312854Sgabeblack@google.com
118412854Sgabeblack@google.com        y += carry;
118512854Sgabeblack@google.com        carry = y < carry;
118612854Sgabeblack@google.com        y += x;
118712854Sgabeblack@google.com        carry += y < x;
118812854Sgabeblack@google.com        result[index] = y;
118912854Sgabeblack@google.com    } while (++index < size);
119012854Sgabeblack@google.com
119112854Sgabeblack@google.com    return (carry ? 1 : 0);
119212854Sgabeblack@google.com}
119312854Sgabeblack@google.com
119412854Sgabeblack@google.comstatic inline int
119512854Sgabeblack@google.comsub_mants(int size, scfx_mant &result, const scfx_mant &a, const scfx_mant &b)
119612854Sgabeblack@google.com{
119712854Sgabeblack@google.com    unsigned carry = 0;
119812854Sgabeblack@google.com
119912854Sgabeblack@google.com    int index = 0;
120012854Sgabeblack@google.com
120112854Sgabeblack@google.com    do {
120212854Sgabeblack@google.com        word x = a[index];
120312854Sgabeblack@google.com        word y = b[index];
120412854Sgabeblack@google.com
120512854Sgabeblack@google.com        y += carry;
120612854Sgabeblack@google.com        carry = y < carry;
120712854Sgabeblack@google.com        y = x - y;
120812854Sgabeblack@google.com        carry += y > x;
120912854Sgabeblack@google.com        result[index] = y;
121012854Sgabeblack@google.com    } while (++index < size);
121112854Sgabeblack@google.com
121212854Sgabeblack@google.com    return (carry ? 1 : 0);
121312854Sgabeblack@google.com}
121412854Sgabeblack@google.com
121512854Sgabeblack@google.comscfx_rep *
121612854Sgabeblack@google.comadd_scfx_rep(const scfx_rep &lhs, const scfx_rep &rhs, int max_wl)
121712854Sgabeblack@google.com{
121812854Sgabeblack@google.com    scfx_rep &result = *new scfx_rep;
121912854Sgabeblack@google.com
122012854Sgabeblack@google.com    //
122112854Sgabeblack@google.com    // check for special cases
122212854Sgabeblack@google.com    //
122312854Sgabeblack@google.com    if (lhs.is_nan() || rhs.is_nan() ||
122412854Sgabeblack@google.com        (lhs.is_inf() && rhs.is_inf() && lhs.m_sign != rhs.m_sign)) {
122512854Sgabeblack@google.com        result.set_nan();
122612854Sgabeblack@google.com        return &result;
122712854Sgabeblack@google.com    }
122812854Sgabeblack@google.com
122912854Sgabeblack@google.com    if (lhs.is_inf()) {
123012854Sgabeblack@google.com        result.set_inf(lhs.m_sign);
123112854Sgabeblack@google.com        return &result;
123212854Sgabeblack@google.com    }
123312854Sgabeblack@google.com
123412854Sgabeblack@google.com    if (rhs.is_inf()) {
123512854Sgabeblack@google.com        result.set_inf(rhs.m_sign);
123612854Sgabeblack@google.com        return &result;
123712854Sgabeblack@google.com    }
123812854Sgabeblack@google.com
123912854Sgabeblack@google.com    //
124012854Sgabeblack@google.com    // align operands if needed
124112854Sgabeblack@google.com    //
124212854Sgabeblack@google.com    scfx_mant_ref lhs_mant;
124312854Sgabeblack@google.com    scfx_mant_ref rhs_mant;
124412854Sgabeblack@google.com
124512854Sgabeblack@google.com    int len_mant = lhs.size();
124612854Sgabeblack@google.com    int new_wp = lhs.m_wp;
124712854Sgabeblack@google.com
124812854Sgabeblack@google.com    align(lhs, rhs, new_wp, len_mant, lhs_mant, rhs_mant);
124912854Sgabeblack@google.com
125012854Sgabeblack@google.com    //
125112854Sgabeblack@google.com    // size the result mantissa
125212854Sgabeblack@google.com    //
125312854Sgabeblack@google.com    result.resize_to(len_mant);
125412854Sgabeblack@google.com    result.m_wp = new_wp;
125512854Sgabeblack@google.com
125612854Sgabeblack@google.com    //
125712854Sgabeblack@google.com    // do it
125812854Sgabeblack@google.com    //
125912854Sgabeblack@google.com    if (lhs.m_sign == rhs.m_sign) {
126012854Sgabeblack@google.com        add_mants(len_mant, result.m_mant, lhs_mant, rhs_mant);
126112854Sgabeblack@google.com        result.m_sign = lhs.m_sign;
126212854Sgabeblack@google.com    } else {
126312854Sgabeblack@google.com        int cmp = compare_abs(lhs, rhs);
126412854Sgabeblack@google.com
126512854Sgabeblack@google.com        if (cmp == 1) {
126612854Sgabeblack@google.com            sub_mants(len_mant, result.m_mant, lhs_mant, rhs_mant);
126712854Sgabeblack@google.com            result.m_sign = lhs.m_sign;
126812854Sgabeblack@google.com        } else if (cmp == -1) {
126912854Sgabeblack@google.com            sub_mants(len_mant, result.m_mant, rhs_mant, lhs_mant);
127012854Sgabeblack@google.com            result.m_sign = rhs.m_sign;
127112854Sgabeblack@google.com        } else {
127212854Sgabeblack@google.com            result.m_mant.clear();
127312854Sgabeblack@google.com            result.m_sign = 1;
127412854Sgabeblack@google.com        }
127512854Sgabeblack@google.com    }
127612854Sgabeblack@google.com
127712854Sgabeblack@google.com    result.find_sw();
127812854Sgabeblack@google.com    result.round(max_wl);
127912854Sgabeblack@google.com
128012854Sgabeblack@google.com    return &result;
128112854Sgabeblack@google.com}
128212854Sgabeblack@google.com
128312854Sgabeblack@google.com
128412854Sgabeblack@google.com// ----------------------------------------------------------------------------
128512854Sgabeblack@google.com//  SUB
128612854Sgabeblack@google.com//
128712854Sgabeblack@google.com//  sub two word's of the same size
128812854Sgabeblack@google.com//  result has the same size
128912854Sgabeblack@google.com//  returns carry of operation
129012854Sgabeblack@google.com// ----------------------------------------------------------------------------
129112854Sgabeblack@google.com
129212854Sgabeblack@google.comstatic inline int
129312854Sgabeblack@google.comsub_with_index(scfx_mant &a, int a_msw, int /*a_lsw*/,
129412854Sgabeblack@google.com               const scfx_mant &b, int b_msw, int b_lsw)
129512854Sgabeblack@google.com{
129612854Sgabeblack@google.com    unsigned carry = 0;
129712854Sgabeblack@google.com
129812854Sgabeblack@google.com    int size = b_msw - b_lsw;
129912854Sgabeblack@google.com    int a_index = a_msw - size;
130012854Sgabeblack@google.com    int b_index = b_msw - size;
130112854Sgabeblack@google.com
130212854Sgabeblack@google.com    do {
130312854Sgabeblack@google.com        word x = a[a_index];
130412854Sgabeblack@google.com        word y = b[b_index];
130512854Sgabeblack@google.com
130612854Sgabeblack@google.com        y += carry;
130712854Sgabeblack@google.com        carry = y < carry;
130812854Sgabeblack@google.com        y = x - y;
130912854Sgabeblack@google.com        carry += y > x;
131012854Sgabeblack@google.com        a[a_index] = y;
131112854Sgabeblack@google.com
131212854Sgabeblack@google.com        a_index++;
131312854Sgabeblack@google.com        b_index++;
131412854Sgabeblack@google.com    } while (size--);
131512854Sgabeblack@google.com
131612854Sgabeblack@google.com    if (carry) {
131712854Sgabeblack@google.com        // special case: a[a_msw + 1] == 1
131812854Sgabeblack@google.com        a[a_msw + 1] = 0;
131912854Sgabeblack@google.com    }
132012854Sgabeblack@google.com
132112854Sgabeblack@google.com    return (carry ? 1 : 0);
132212854Sgabeblack@google.com}
132312854Sgabeblack@google.com
132412854Sgabeblack@google.comscfx_rep *
132512854Sgabeblack@google.comsub_scfx_rep(const scfx_rep &lhs, const scfx_rep &rhs, int max_wl)
132612854Sgabeblack@google.com{
132712854Sgabeblack@google.com    scfx_rep &result = *new scfx_rep;
132812854Sgabeblack@google.com
132912854Sgabeblack@google.com    //
133012854Sgabeblack@google.com    // check for special cases
133112854Sgabeblack@google.com    //
133212854Sgabeblack@google.com    if (lhs.is_nan() || rhs.is_nan() ||
133312854Sgabeblack@google.com        (lhs.is_inf() && rhs.is_inf() && lhs.m_sign == rhs.m_sign)) {
133412854Sgabeblack@google.com        result.set_nan();
133512854Sgabeblack@google.com        return &result;
133612854Sgabeblack@google.com    }
133712854Sgabeblack@google.com
133812854Sgabeblack@google.com    if (lhs.is_inf()) {
133912854Sgabeblack@google.com        result.set_inf(lhs.m_sign);
134012854Sgabeblack@google.com        return &result;
134112854Sgabeblack@google.com    }
134212854Sgabeblack@google.com
134312854Sgabeblack@google.com    if (rhs.is_inf()) {
134412854Sgabeblack@google.com        result.set_inf(-1 * rhs.m_sign);
134512854Sgabeblack@google.com        return &result;
134612854Sgabeblack@google.com    }
134712854Sgabeblack@google.com
134812854Sgabeblack@google.com    //
134912854Sgabeblack@google.com    // align operands if needed
135012854Sgabeblack@google.com    //
135112854Sgabeblack@google.com    scfx_mant_ref lhs_mant;
135212854Sgabeblack@google.com    scfx_mant_ref rhs_mant;
135312854Sgabeblack@google.com
135412854Sgabeblack@google.com    int len_mant = lhs.size();
135512854Sgabeblack@google.com    int new_wp = lhs.m_wp;
135612854Sgabeblack@google.com
135712854Sgabeblack@google.com    align(lhs, rhs, new_wp, len_mant, lhs_mant, rhs_mant);
135812854Sgabeblack@google.com
135912854Sgabeblack@google.com    //
136012854Sgabeblack@google.com    // size the result mantissa
136112854Sgabeblack@google.com    //
136212854Sgabeblack@google.com    result.resize_to(len_mant);
136312854Sgabeblack@google.com    result.m_wp = new_wp;
136412854Sgabeblack@google.com
136512854Sgabeblack@google.com    //
136612854Sgabeblack@google.com    // do it
136712854Sgabeblack@google.com    //
136812854Sgabeblack@google.com    if (lhs.m_sign != rhs.m_sign) {
136912854Sgabeblack@google.com        add_mants(len_mant, result.m_mant, lhs_mant, rhs_mant);
137012854Sgabeblack@google.com        result.m_sign = lhs.m_sign;
137112854Sgabeblack@google.com    } else {
137212854Sgabeblack@google.com        int cmp = compare_abs(lhs, rhs);
137312854Sgabeblack@google.com
137412854Sgabeblack@google.com        if (cmp == 1) {
137512854Sgabeblack@google.com            sub_mants(len_mant, result.m_mant, lhs_mant, rhs_mant);
137612854Sgabeblack@google.com            result.m_sign = lhs.m_sign;
137712854Sgabeblack@google.com        } else if (cmp == -1) {
137812854Sgabeblack@google.com            sub_mants(len_mant, result.m_mant, rhs_mant, lhs_mant);
137912854Sgabeblack@google.com            result.m_sign = -rhs.m_sign;
138012854Sgabeblack@google.com        } else {
138112854Sgabeblack@google.com            result.m_mant.clear();
138212854Sgabeblack@google.com            result.m_sign = 1;
138312854Sgabeblack@google.com        }
138412854Sgabeblack@google.com    }
138512854Sgabeblack@google.com
138612854Sgabeblack@google.com    result.find_sw();
138712854Sgabeblack@google.com    result.round(max_wl);
138812854Sgabeblack@google.com
138912854Sgabeblack@google.com    return &result;
139012854Sgabeblack@google.com}
139112854Sgabeblack@google.com
139212854Sgabeblack@google.com
139312854Sgabeblack@google.com// ----------------------------------------------------------------------------
139412854Sgabeblack@google.com//  MUL
139512854Sgabeblack@google.com// ----------------------------------------------------------------------------
139612854Sgabeblack@google.com
139712854Sgabeblack@google.comunion word_short
139812854Sgabeblack@google.com{
139912854Sgabeblack@google.com    word l;
140012854Sgabeblack@google.com    struct
140112854Sgabeblack@google.com    {
140212854Sgabeblack@google.com#if defined(SC_BOOST_BIG_ENDIAN)
140312854Sgabeblack@google.com        half_word u;
140412854Sgabeblack@google.com        half_word l;
140512854Sgabeblack@google.com#elif defined(SC_BOOST_LITTLE_ENDIAN)
140612854Sgabeblack@google.com        half_word l;
140712854Sgabeblack@google.com        half_word u;
140812854Sgabeblack@google.com#endif
140912854Sgabeblack@google.com    } s;
141012854Sgabeblack@google.com};
141112854Sgabeblack@google.com
141212854Sgabeblack@google.com#if defined(SC_BOOST_BIG_ENDIAN)
141312854Sgabeblack@google.comstatic const int half_word_incr = -1;
141412854Sgabeblack@google.com#elif defined(SC_BOOST_LITTLE_ENDIAN)
141512854Sgabeblack@google.comstatic const int half_word_incr = 1;
141612854Sgabeblack@google.com#endif
141712854Sgabeblack@google.com
141812854Sgabeblack@google.comvoid
141912854Sgabeblack@google.commultiply(scfx_rep &result, const scfx_rep &lhs, const scfx_rep &rhs,
142012854Sgabeblack@google.com         int max_wl)
142112854Sgabeblack@google.com{
142212854Sgabeblack@google.com    //
142312854Sgabeblack@google.com    // check for special cases
142412854Sgabeblack@google.com    //
142512854Sgabeblack@google.com    if (lhs.is_nan() || rhs.is_nan() ||
142612854Sgabeblack@google.com        (lhs.is_inf() && rhs.is_zero()) ||
142712854Sgabeblack@google.com        (lhs.is_zero() && rhs.is_inf())) {
142812854Sgabeblack@google.com        result.set_nan();
142912854Sgabeblack@google.com        return;
143012854Sgabeblack@google.com    }
143112854Sgabeblack@google.com
143212854Sgabeblack@google.com    if (lhs.is_inf() || rhs.is_inf()) {
143312854Sgabeblack@google.com        result.set_inf(lhs.m_sign * rhs.m_sign);
143412854Sgabeblack@google.com        return;
143512854Sgabeblack@google.com    }
143612854Sgabeblack@google.com
143712854Sgabeblack@google.com    if (lhs.is_zero() || rhs.is_zero()) {
143812854Sgabeblack@google.com        result.set_zero(lhs.m_sign * rhs.m_sign);
143912854Sgabeblack@google.com        return;
144012854Sgabeblack@google.com    }
144112854Sgabeblack@google.com
144212854Sgabeblack@google.com    //
144312854Sgabeblack@google.com    // do it
144412854Sgabeblack@google.com    //
144512854Sgabeblack@google.com    int len_lhs = lhs.m_msw - lhs.m_lsw + 1;
144612854Sgabeblack@google.com    int len_rhs = rhs.m_msw - rhs.m_lsw + 1;
144712854Sgabeblack@google.com
144812854Sgabeblack@google.com    int new_size = sc_max(min_mant, len_lhs + len_rhs);
144912854Sgabeblack@google.com    int new_wp = (lhs.m_wp - lhs.m_lsw) + (rhs.m_wp - rhs.m_lsw);
145012854Sgabeblack@google.com    int new_sign = lhs.m_sign * rhs.m_sign;
145112854Sgabeblack@google.com
145212854Sgabeblack@google.com    result.resize_to(new_size);
145312854Sgabeblack@google.com    result.m_mant.clear();
145412854Sgabeblack@google.com    result.m_wp = new_wp;
145512854Sgabeblack@google.com    result.m_sign = new_sign;
145612854Sgabeblack@google.com    result.m_state = scfx_rep::normal;
145712854Sgabeblack@google.com
145812854Sgabeblack@google.com    half_word *s1 = lhs.m_mant.half_addr(lhs.m_lsw);
145912854Sgabeblack@google.com    half_word *s2 = rhs.m_mant.half_addr(rhs.m_lsw);
146012854Sgabeblack@google.com
146112854Sgabeblack@google.com    half_word *t = result.m_mant.half_addr();
146212854Sgabeblack@google.com
146312854Sgabeblack@google.com    len_lhs <<= 1;
146412854Sgabeblack@google.com    len_rhs <<= 1;
146512854Sgabeblack@google.com
146612854Sgabeblack@google.com    int i1, i2;
146712854Sgabeblack@google.com
146812854Sgabeblack@google.com    for (i1 = 0; i1 * half_word_incr < len_lhs; i1 += half_word_incr) {
146912854Sgabeblack@google.com        word_short ls;
147012854Sgabeblack@google.com        ls.l = 0;
147112854Sgabeblack@google.com
147212854Sgabeblack@google.com        half_word v1 = s1[i1];
147312854Sgabeblack@google.com
147412854Sgabeblack@google.com        for (i2  = 0; i2 * half_word_incr < len_rhs; i2 += half_word_incr) {
147512854Sgabeblack@google.com            ls.l  += v1 * s2[i2];
147612854Sgabeblack@google.com            ls.s.l = ls.s.u + ((t[i2] += ls.s.l) < ls.s.l);
147712854Sgabeblack@google.com            ls.s.u = 0;
147812854Sgabeblack@google.com        }
147912854Sgabeblack@google.com
148012854Sgabeblack@google.com        t[i2] = ls.s.l;
148112854Sgabeblack@google.com        t += half_word_incr;
148212854Sgabeblack@google.com    }
148312854Sgabeblack@google.com
148412854Sgabeblack@google.com    result.find_sw();
148512854Sgabeblack@google.com    result.round(max_wl);
148612854Sgabeblack@google.com}
148712854Sgabeblack@google.com
148812854Sgabeblack@google.com
148912854Sgabeblack@google.com// ----------------------------------------------------------------------------
149012854Sgabeblack@google.com//  DIV
149112854Sgabeblack@google.com// ----------------------------------------------------------------------------
149212854Sgabeblack@google.com
149312854Sgabeblack@google.comscfx_rep *
149412854Sgabeblack@google.comdiv_scfx_rep(const scfx_rep &lhs, const scfx_rep &rhs, int div_wl)
149512854Sgabeblack@google.com{
149612854Sgabeblack@google.com    scfx_rep &result = *new scfx_rep;
149712854Sgabeblack@google.com
149812854Sgabeblack@google.com    //
149912854Sgabeblack@google.com    // check for special cases
150012854Sgabeblack@google.com    //
150112854Sgabeblack@google.com    if (lhs.is_nan() || rhs.is_nan() || (lhs.is_inf() && rhs.is_inf()) ||
150212854Sgabeblack@google.com        (lhs.is_zero() && rhs.is_zero())) {
150312854Sgabeblack@google.com        result.set_nan();
150412854Sgabeblack@google.com        return &result;
150512854Sgabeblack@google.com    }
150612854Sgabeblack@google.com
150712854Sgabeblack@google.com    if (lhs.is_inf() || rhs.is_zero()) {
150812854Sgabeblack@google.com        result.set_inf(lhs.m_sign * rhs.m_sign);
150912854Sgabeblack@google.com        return &result;
151012854Sgabeblack@google.com    }
151112854Sgabeblack@google.com
151212854Sgabeblack@google.com    if (lhs.is_zero() || rhs.is_inf()) {
151312854Sgabeblack@google.com        result.set_zero(lhs.m_sign * rhs.m_sign);
151412854Sgabeblack@google.com        return &result;
151512854Sgabeblack@google.com    }
151612854Sgabeblack@google.com
151712854Sgabeblack@google.com    //
151812854Sgabeblack@google.com    // do it
151912854Sgabeblack@google.com    //
152012854Sgabeblack@google.com
152112854Sgabeblack@google.com    // compute one bit more for rounding
152212854Sgabeblack@google.com    div_wl++;
152312854Sgabeblack@google.com
152412854Sgabeblack@google.com    result.resize_to(sc_max(n_word(div_wl) + 1, min_mant));
152512854Sgabeblack@google.com    result.m_mant.clear();
152612854Sgabeblack@google.com    result.m_sign = lhs.m_sign * rhs.m_sign;
152712854Sgabeblack@google.com
152812854Sgabeblack@google.com    int msb_lhs = scfx_find_msb(lhs.m_mant[lhs.m_msw]) +
152912854Sgabeblack@google.com                  (lhs.m_msw - lhs.m_wp) * bits_in_word;
153012854Sgabeblack@google.com    int msb_rhs = scfx_find_msb(rhs.m_mant[rhs.m_msw]) +
153112854Sgabeblack@google.com                  (rhs.m_msw - rhs.m_wp) * bits_in_word;
153212854Sgabeblack@google.com
153312854Sgabeblack@google.com    int msb_res = msb_lhs - msb_rhs;
153412854Sgabeblack@google.com    int to_shift = -msb_res % bits_in_word;
153512854Sgabeblack@google.com    int result_index;
153612854Sgabeblack@google.com
153712854Sgabeblack@google.com    int c = (msb_res % bits_in_word >= 0) ? 1 : 0;
153812854Sgabeblack@google.com
153912854Sgabeblack@google.com    result_index = (result.size() - c) * bits_in_word + msb_res % bits_in_word;
154012854Sgabeblack@google.com    result.m_wp = (result.size() - c) - msb_res / bits_in_word;
154112854Sgabeblack@google.com
154212854Sgabeblack@google.com    scfx_rep remainder = lhs;
154312854Sgabeblack@google.com
154412854Sgabeblack@google.com    // align msb from remainder to msb from rhs
154512854Sgabeblack@google.com    remainder.lshift(to_shift);
154612854Sgabeblack@google.com
154712854Sgabeblack@google.com    // make sure msw(remainder) < size - 1
154812854Sgabeblack@google.com    if (remainder.m_msw == remainder.size() - 1)
154912854Sgabeblack@google.com        remainder.resize_to(remainder.size() + 1, 1);
155012854Sgabeblack@google.com
155112854Sgabeblack@google.com    // make sure msw(remainder) >= msw(rhs)!
155212854Sgabeblack@google.com    int msw_diff = rhs.m_msw - remainder.m_msw;
155312854Sgabeblack@google.com    if (msw_diff > 0)
155412854Sgabeblack@google.com        remainder.resize_to(remainder.size() + msw_diff, -1);
155512854Sgabeblack@google.com
155612854Sgabeblack@google.com    int counter;
155712854Sgabeblack@google.com
155812854Sgabeblack@google.com    for (counter = div_wl; counter && !remainder.is_zero(); counter--) {
155912854Sgabeblack@google.com        if (compare_msw_ff(rhs, remainder) <= 0) {
156012854Sgabeblack@google.com            result.set_bin(result_index);
156112854Sgabeblack@google.com            sub_with_index(remainder.m_mant, remainder.m_msw, remainder.m_lsw,
156212854Sgabeblack@google.com                           rhs.m_mant, rhs.m_msw, rhs.m_lsw);
156312854Sgabeblack@google.com        }
156412854Sgabeblack@google.com        result_index--;
156512854Sgabeblack@google.com        remainder.shift_left(1);
156612854Sgabeblack@google.com        remainder.m_lsw = remainder.find_lsw();
156712854Sgabeblack@google.com    }
156812854Sgabeblack@google.com
156912854Sgabeblack@google.com    // perform convergent rounding, if needed
157012854Sgabeblack@google.com    if (counter == 0) {
157112854Sgabeblack@google.com        int index = result_index + 1 - result.m_wp * bits_in_word;
157212854Sgabeblack@google.com
157312854Sgabeblack@google.com        scfx_index x = result.calc_indices(index);
157412854Sgabeblack@google.com        scfx_index x1 = result.calc_indices(index + 1);
157512854Sgabeblack@google.com
157612854Sgabeblack@google.com        if (result.o_bit_at(x) && result.o_bit_at(x1))
157712854Sgabeblack@google.com            result.q_incr(x);
157812854Sgabeblack@google.com
157912854Sgabeblack@google.com        result.m_r_flag = true;
158012854Sgabeblack@google.com    }
158112854Sgabeblack@google.com
158212854Sgabeblack@google.com    result.find_sw();
158312854Sgabeblack@google.com
158412854Sgabeblack@google.com    return &result;
158512854Sgabeblack@google.com}
158612854Sgabeblack@google.com
158712854Sgabeblack@google.com// ----------------------------------------------------------------------------
158812854Sgabeblack@google.com//  destructive shift mantissa to the left
158912854Sgabeblack@google.com// ----------------------------------------------------------------------------
159012854Sgabeblack@google.com
159112854Sgabeblack@google.comvoid
159212854Sgabeblack@google.comscfx_rep::lshift(int n)
159312854Sgabeblack@google.com{
159412854Sgabeblack@google.com    if (n == 0)
159512854Sgabeblack@google.com        return;
159612854Sgabeblack@google.com
159712854Sgabeblack@google.com    if (n < 0) {
159812854Sgabeblack@google.com        rshift(-n);
159912854Sgabeblack@google.com        return;
160012854Sgabeblack@google.com    }
160112854Sgabeblack@google.com
160212854Sgabeblack@google.com    if (is_normal()) {
160312854Sgabeblack@google.com        int shift_bits = n % bits_in_word;
160412854Sgabeblack@google.com        int shift_words = n / bits_in_word;
160512854Sgabeblack@google.com
160612854Sgabeblack@google.com        // resize if needed
160712854Sgabeblack@google.com        if (m_msw == size() - 1 &&
160812854Sgabeblack@google.com            scfx_find_msb(m_mant[m_msw]) >= bits_in_word - shift_bits)
160912854Sgabeblack@google.com            resize_to(size() + 1, 1);
161012854Sgabeblack@google.com
161112854Sgabeblack@google.com        // do it
161212854Sgabeblack@google.com        m_wp -= shift_words;
161312854Sgabeblack@google.com        shift_left(shift_bits);
161412854Sgabeblack@google.com        find_sw();
161512854Sgabeblack@google.com    }
161612854Sgabeblack@google.com}
161712854Sgabeblack@google.com
161812854Sgabeblack@google.com// ----------------------------------------------------------------------------
161912854Sgabeblack@google.com//  destructive shift mantissa to the right
162012854Sgabeblack@google.com// ----------------------------------------------------------------------------
162112854Sgabeblack@google.com
162212854Sgabeblack@google.comvoid
162312854Sgabeblack@google.comscfx_rep::rshift(int n)
162412854Sgabeblack@google.com{
162512854Sgabeblack@google.com    if (n == 0)
162612854Sgabeblack@google.com        return;
162712854Sgabeblack@google.com
162812854Sgabeblack@google.com    if (n < 0) {
162912854Sgabeblack@google.com        lshift(-n);
163012854Sgabeblack@google.com        return;
163112854Sgabeblack@google.com    }
163212854Sgabeblack@google.com
163312854Sgabeblack@google.com    if (is_normal()) {
163412854Sgabeblack@google.com        int shift_bits = n % bits_in_word;
163512854Sgabeblack@google.com        int shift_words = n / bits_in_word;
163612854Sgabeblack@google.com
163712854Sgabeblack@google.com        // resize if needed
163812854Sgabeblack@google.com        if (m_lsw == 0 && scfx_find_lsb(m_mant[m_lsw]) < shift_bits)
163912854Sgabeblack@google.com            resize_to(size() + 1, -1);
164012854Sgabeblack@google.com
164112854Sgabeblack@google.com        // do it
164212854Sgabeblack@google.com        m_wp += shift_words;
164312854Sgabeblack@google.com        shift_right(shift_bits);
164412854Sgabeblack@google.com        find_sw();
164512854Sgabeblack@google.com    }
164612854Sgabeblack@google.com}
164712854Sgabeblack@google.com
164812854Sgabeblack@google.com
164912854Sgabeblack@google.com// ----------------------------------------------------------------------------
165012854Sgabeblack@google.com//  FRIEND FUNCTION : compare_abs
165112854Sgabeblack@google.com//
165212854Sgabeblack@google.com//  Compares the absolute values of two scfx_reps, excluding the special cases.
165312854Sgabeblack@google.com// ----------------------------------------------------------------------------
165412854Sgabeblack@google.com
165512854Sgabeblack@google.comint
165612854Sgabeblack@google.comcompare_abs(const scfx_rep &a, const scfx_rep &b)
165712854Sgabeblack@google.com{
165812854Sgabeblack@google.com    // check for zero
165912854Sgabeblack@google.com    word a_word = a.m_mant[a.m_msw];
166012854Sgabeblack@google.com    word b_word = b.m_mant[b.m_msw];
166112854Sgabeblack@google.com
166212854Sgabeblack@google.com    if (a_word == 0 || b_word == 0) {
166312854Sgabeblack@google.com        if (a_word != 0)
166412854Sgabeblack@google.com            return 1;
166512854Sgabeblack@google.com        if (b_word != 0)
166612854Sgabeblack@google.com            return -1;
166712854Sgabeblack@google.com        return 0;
166812854Sgabeblack@google.com    }
166912854Sgabeblack@google.com
167012854Sgabeblack@google.com    // compare msw index
167112854Sgabeblack@google.com    int a_msw = a.m_msw - a.m_wp;
167212854Sgabeblack@google.com    int b_msw = b.m_msw - b.m_wp;
167312854Sgabeblack@google.com
167412854Sgabeblack@google.com    if (a_msw > b_msw)
167512854Sgabeblack@google.com        return 1;
167612854Sgabeblack@google.com
167712854Sgabeblack@google.com    if (a_msw < b_msw)
167812854Sgabeblack@google.com        return -1;
167912854Sgabeblack@google.com
168012854Sgabeblack@google.com    // compare content
168112854Sgabeblack@google.com    int a_i = a.m_msw;
168212854Sgabeblack@google.com    int b_i = b.m_msw;
168312854Sgabeblack@google.com
168412854Sgabeblack@google.com    while (a_i >= a.m_lsw && b_i >= b.m_lsw) {
168512854Sgabeblack@google.com        a_word = a.m_mant[a_i];
168612854Sgabeblack@google.com        b_word = b.m_mant[b_i];
168712854Sgabeblack@google.com        if (a_word > b_word)
168812854Sgabeblack@google.com            return 1;
168912854Sgabeblack@google.com        if (a_word < b_word)
169012854Sgabeblack@google.com            return -1;
169112854Sgabeblack@google.com        --a_i;
169212854Sgabeblack@google.com        --b_i;
169312854Sgabeblack@google.com    }
169412854Sgabeblack@google.com
169512854Sgabeblack@google.com    bool a_zero = true;
169612854Sgabeblack@google.com    while (a_i >= a.m_lsw) {
169712854Sgabeblack@google.com        a_zero = a_zero && (a.m_mant[a_i] == 0);
169812854Sgabeblack@google.com        --a_i;
169912854Sgabeblack@google.com    }
170012854Sgabeblack@google.com
170112854Sgabeblack@google.com    bool b_zero = true;
170212854Sgabeblack@google.com    while (b_i >= b.m_lsw) {
170312854Sgabeblack@google.com        b_zero = b_zero && (b.m_mant[b_i] == 0);
170412854Sgabeblack@google.com        --b_i;
170512854Sgabeblack@google.com    }
170612854Sgabeblack@google.com
170712854Sgabeblack@google.com    // assertion: a_zero || b_zero
170812854Sgabeblack@google.com
170912854Sgabeblack@google.com    if (!a_zero && b_zero)
171012854Sgabeblack@google.com        return 1;
171112854Sgabeblack@google.com
171212854Sgabeblack@google.com    if (a_zero && !b_zero)
171312854Sgabeblack@google.com        return -1;
171412854Sgabeblack@google.com
171512854Sgabeblack@google.com    return 0;
171612854Sgabeblack@google.com}
171712854Sgabeblack@google.com
171812854Sgabeblack@google.com// ----------------------------------------------------------------------------
171912854Sgabeblack@google.com//  FRIEND FUNCTION : cmp_scfx_rep
172012854Sgabeblack@google.com//
172112854Sgabeblack@google.com//  Compares the values of two scfx_reps, including the special cases.
172212854Sgabeblack@google.com// ----------------------------------------------------------------------------
172312854Sgabeblack@google.com
172412854Sgabeblack@google.comint
172512854Sgabeblack@google.comcmp_scfx_rep(const scfx_rep &a, const scfx_rep &b)
172612854Sgabeblack@google.com{
172712854Sgabeblack@google.com    // handle special cases
172812854Sgabeblack@google.com
172912854Sgabeblack@google.com    if (a.is_nan() || b.is_nan()) {
173012854Sgabeblack@google.com        return 2;
173112854Sgabeblack@google.com    }
173212854Sgabeblack@google.com
173312854Sgabeblack@google.com    if (a.is_inf() || b.is_inf()) {
173412854Sgabeblack@google.com        if (a.is_inf()) {
173512854Sgabeblack@google.com            if (!a.is_neg()) {
173612854Sgabeblack@google.com                if (b.is_inf() && !b.is_neg()) {
173712854Sgabeblack@google.com                    return 0;
173812854Sgabeblack@google.com                } else {
173912854Sgabeblack@google.com                    return 1;
174012854Sgabeblack@google.com                }
174112854Sgabeblack@google.com            } else {
174212854Sgabeblack@google.com                if (b.is_inf() && b.is_neg()) {
174312854Sgabeblack@google.com                    return 0;
174412854Sgabeblack@google.com                } else {
174512854Sgabeblack@google.com                    return -1;
174612854Sgabeblack@google.com                }
174712854Sgabeblack@google.com            }
174812854Sgabeblack@google.com        }
174912854Sgabeblack@google.com        if (b.is_inf()) {
175012854Sgabeblack@google.com            if (!b.is_neg()) {
175112854Sgabeblack@google.com                return -1;
175212854Sgabeblack@google.com            } else {
175312854Sgabeblack@google.com                return 1;
175412854Sgabeblack@google.com            }
175512854Sgabeblack@google.com        }
175612854Sgabeblack@google.com    }
175712854Sgabeblack@google.com
175812854Sgabeblack@google.com    if (a.is_zero() && b.is_zero()) {
175912854Sgabeblack@google.com        return 0;
176012854Sgabeblack@google.com    }
176112854Sgabeblack@google.com
176212854Sgabeblack@google.com    // compare sign
176312854Sgabeblack@google.com    if (a.m_sign != b.m_sign) {
176412854Sgabeblack@google.com        return a.m_sign;
176512854Sgabeblack@google.com    }
176612854Sgabeblack@google.com
176712854Sgabeblack@google.com    return (a.m_sign * compare_abs(a, b));
176812854Sgabeblack@google.com}
176912854Sgabeblack@google.com
177012854Sgabeblack@google.com
177112854Sgabeblack@google.com// ----------------------------------------------------------------------------
177212854Sgabeblack@google.com//  PRIVATE METHOD : quantization
177312854Sgabeblack@google.com//
177412854Sgabeblack@google.com//  Performs destructive quantization.
177512854Sgabeblack@google.com// ----------------------------------------------------------------------------
177612854Sgabeblack@google.com
177712854Sgabeblack@google.comvoid
177812854Sgabeblack@google.comscfx_rep::quantization(const scfx_params &params, bool &q_flag)
177912854Sgabeblack@google.com{
178012854Sgabeblack@google.com    scfx_index x = calc_indices(params.iwl() - params.wl());
178112854Sgabeblack@google.com
178212854Sgabeblack@google.com    if (x.wi() < 0)
178312854Sgabeblack@google.com        return;
178412854Sgabeblack@google.com
178512854Sgabeblack@google.com    if (x.wi() >= size())
178612854Sgabeblack@google.com        resize_to(x.wi() + 1, 1);
178712854Sgabeblack@google.com
178812854Sgabeblack@google.com    bool qb = q_bit(x);
178912854Sgabeblack@google.com    bool qz = q_zero(x);
179012854Sgabeblack@google.com
179112854Sgabeblack@google.com    q_flag = (qb || ! qz);
179212854Sgabeblack@google.com
179312854Sgabeblack@google.com    if (q_flag) {
179412854Sgabeblack@google.com        switch (params.q_mode()) {
179512854Sgabeblack@google.com          case SC_TRN: // truncation
179612854Sgabeblack@google.com            {
179712854Sgabeblack@google.com                if (is_neg())
179812854Sgabeblack@google.com                    q_incr(x);
179912854Sgabeblack@google.com                break;
180012854Sgabeblack@google.com            }
180112854Sgabeblack@google.com          case SC_RND: // rounding to plus infinity
180212854Sgabeblack@google.com            {
180312854Sgabeblack@google.com                if (!is_neg()) {
180412854Sgabeblack@google.com                    if (qb)
180512854Sgabeblack@google.com                        q_incr(x);
180612854Sgabeblack@google.com                } else {
180712854Sgabeblack@google.com                    if (qb && !qz)
180812854Sgabeblack@google.com                        q_incr(x);
180912854Sgabeblack@google.com                }
181012854Sgabeblack@google.com                break;
181112854Sgabeblack@google.com            }
181212854Sgabeblack@google.com          case SC_TRN_ZERO: // truncation to zero
181312854Sgabeblack@google.com            {
181412854Sgabeblack@google.com                break;
181512854Sgabeblack@google.com            }
181612854Sgabeblack@google.com          case SC_RND_INF: // rounding to infinity
181712854Sgabeblack@google.com            {
181812854Sgabeblack@google.com                if (qb)
181912854Sgabeblack@google.com                    q_incr(x);
182012854Sgabeblack@google.com                break;
182112854Sgabeblack@google.com            }
182212854Sgabeblack@google.com          case SC_RND_CONV: // convergent rounding
182312854Sgabeblack@google.com            {
182412854Sgabeblack@google.com                if ((qb && !qz) || (qb && qz && q_odd(x)))
182512854Sgabeblack@google.com                    q_incr(x);
182612854Sgabeblack@google.com                break;
182712854Sgabeblack@google.com            }
182812854Sgabeblack@google.com          case SC_RND_ZERO: // rounding to zero
182912854Sgabeblack@google.com            {
183012854Sgabeblack@google.com                if (qb && !qz)
183112854Sgabeblack@google.com                    q_incr(x);
183212854Sgabeblack@google.com                break;
183312854Sgabeblack@google.com            }
183412854Sgabeblack@google.com          case SC_RND_MIN_INF: // rounding to minus infinity
183512854Sgabeblack@google.com            {
183612854Sgabeblack@google.com                if (!is_neg()) {
183712854Sgabeblack@google.com                    if (qb && !qz)
183812854Sgabeblack@google.com                        q_incr(x);
183912854Sgabeblack@google.com                } else {
184012854Sgabeblack@google.com                    if (qb)
184112854Sgabeblack@google.com                        q_incr(x);
184212854Sgabeblack@google.com                }
184312854Sgabeblack@google.com                break;
184412854Sgabeblack@google.com            }
184512854Sgabeblack@google.com          default:
184612854Sgabeblack@google.com            ;
184712854Sgabeblack@google.com        }
184812854Sgabeblack@google.com        q_clear(x);
184912854Sgabeblack@google.com
185012854Sgabeblack@google.com        find_sw();
185112854Sgabeblack@google.com    }
185212854Sgabeblack@google.com}
185312854Sgabeblack@google.com
185412854Sgabeblack@google.com
185512854Sgabeblack@google.com// ----------------------------------------------------------------------------
185612854Sgabeblack@google.com//  PRIVATE METHOD : overflow
185712854Sgabeblack@google.com//
185812854Sgabeblack@google.com//  Performs destructive overflow handling.
185912854Sgabeblack@google.com// ----------------------------------------------------------------------------
186012854Sgabeblack@google.com
186112854Sgabeblack@google.comvoid
186212854Sgabeblack@google.comscfx_rep::overflow(const scfx_params &params, bool &o_flag)
186312854Sgabeblack@google.com{
186412854Sgabeblack@google.com    scfx_index x = calc_indices(params.iwl() - 1);
186512854Sgabeblack@google.com
186612854Sgabeblack@google.com    if (x.wi() >= size())
186712854Sgabeblack@google.com        resize_to(x.wi() + 1, 1);
186812854Sgabeblack@google.com
186912854Sgabeblack@google.com    if (x.wi() < 0) {
187012854Sgabeblack@google.com        resize_to(size() - x.wi(), -1);
187112854Sgabeblack@google.com        x.wi(0);
187212854Sgabeblack@google.com    }
187312854Sgabeblack@google.com
187412854Sgabeblack@google.com    bool zero_left = o_zero_left(x);
187512854Sgabeblack@google.com    bool bit_at = o_bit_at(x);
187612854Sgabeblack@google.com    bool zero_right = o_zero_right(x);
187712854Sgabeblack@google.com
187812854Sgabeblack@google.com    bool under = false;
187912854Sgabeblack@google.com    bool over = false;
188012854Sgabeblack@google.com
188112854Sgabeblack@google.com    sc_enc enc = params.enc();
188212854Sgabeblack@google.com
188312854Sgabeblack@google.com    if (enc == SC_TC_) {
188412854Sgabeblack@google.com        if (is_neg()) {
188512854Sgabeblack@google.com            if (params.o_mode() == SC_SAT_SYM)
188612854Sgabeblack@google.com                under = (!zero_left || bit_at);
188712854Sgabeblack@google.com            else
188812854Sgabeblack@google.com                under = (!zero_left || (zero_left && bit_at && ! zero_right));
188912854Sgabeblack@google.com        } else {
189012854Sgabeblack@google.com            over = (! zero_left || bit_at);
189112854Sgabeblack@google.com        }
189212854Sgabeblack@google.com    } else {
189312854Sgabeblack@google.com        if (is_neg())
189412854Sgabeblack@google.com            under = (!is_zero());
189512854Sgabeblack@google.com        else
189612854Sgabeblack@google.com            over = (!zero_left);
189712854Sgabeblack@google.com    }
189812854Sgabeblack@google.com
189912854Sgabeblack@google.com    o_flag = (under || over);
190012854Sgabeblack@google.com
190112854Sgabeblack@google.com    if (o_flag) {
190212854Sgabeblack@google.com        scfx_index x2 = calc_indices(params.iwl() - params.wl());
190312854Sgabeblack@google.com
190412854Sgabeblack@google.com        if (x2.wi() < 0) {
190512854Sgabeblack@google.com            resize_to(size() - x2.wi(), -1);
190612854Sgabeblack@google.com            x.wi(x.wi() - x2.wi());
190712854Sgabeblack@google.com            x2.wi(0);
190812854Sgabeblack@google.com        }
190912854Sgabeblack@google.com
191012854Sgabeblack@google.com        switch (params.o_mode()) {
191112854Sgabeblack@google.com          case SC_WRAP: // wrap-around
191212854Sgabeblack@google.com            {
191312854Sgabeblack@google.com                int n_bits = params.n_bits();
191412854Sgabeblack@google.com
191512854Sgabeblack@google.com                if (n_bits == 0) {
191612854Sgabeblack@google.com                    // wrap-around all 'wl' bits
191712854Sgabeblack@google.com                    toggle_tc();
191812854Sgabeblack@google.com                    o_extend(x, enc);
191912854Sgabeblack@google.com                    toggle_tc();
192012854Sgabeblack@google.com                } else if (n_bits < params.wl()) {
192112854Sgabeblack@google.com                    scfx_index x3 = calc_indices(params.iwl() - 1 - n_bits);
192212854Sgabeblack@google.com
192312854Sgabeblack@google.com                    // wrap-around least significant 'wl - n_bits' bits;
192412854Sgabeblack@google.com                    // saturate most significant 'n_bits' bits
192512854Sgabeblack@google.com                    toggle_tc();
192612854Sgabeblack@google.com                    o_set(x, x3, enc, under);
192712854Sgabeblack@google.com                    o_extend(x, enc);
192812854Sgabeblack@google.com                    toggle_tc();
192912854Sgabeblack@google.com                } else {
193012854Sgabeblack@google.com                    // saturate all 'wl' bits
193112854Sgabeblack@google.com                    if (under)
193212854Sgabeblack@google.com                        o_set_low(x, enc);
193312854Sgabeblack@google.com                    else
193412854Sgabeblack@google.com                        o_set_high(x, x2, enc);
193512854Sgabeblack@google.com                }
193612854Sgabeblack@google.com                break;
193712854Sgabeblack@google.com            }
193812854Sgabeblack@google.com          case SC_SAT: // saturation
193912854Sgabeblack@google.com            {
194012854Sgabeblack@google.com                if (under)
194112854Sgabeblack@google.com                    o_set_low(x, enc);
194212854Sgabeblack@google.com                else
194312854Sgabeblack@google.com                    o_set_high(x, x2, enc);
194412854Sgabeblack@google.com                break;
194512854Sgabeblack@google.com            }
194612854Sgabeblack@google.com          case SC_SAT_SYM: // symmetrical saturation
194712854Sgabeblack@google.com            {
194812854Sgabeblack@google.com                if (under) {
194912854Sgabeblack@google.com                    if (enc == SC_TC_)
195012854Sgabeblack@google.com                        o_set_high(x, x2, SC_TC_, -1);
195112854Sgabeblack@google.com                    else
195212854Sgabeblack@google.com                        o_set_low(x, SC_US_);
195312854Sgabeblack@google.com                } else {
195412854Sgabeblack@google.com                    o_set_high(x, x2, enc);
195512854Sgabeblack@google.com                }
195612854Sgabeblack@google.com                break;
195712854Sgabeblack@google.com            }
195812854Sgabeblack@google.com          case SC_SAT_ZERO: // saturation to zero
195912854Sgabeblack@google.com            {
196012854Sgabeblack@google.com                set_zero();
196112854Sgabeblack@google.com                break;
196212854Sgabeblack@google.com            }
196312854Sgabeblack@google.com          case SC_WRAP_SM: // sign magnitude wrap-around
196412854Sgabeblack@google.com            {
196512854Sgabeblack@google.com                SC_ERROR_IF_(enc == SC_US_,
196612854Sgabeblack@google.com                             "SC_WRAP_SM not defined for unsigned numbers");
196712854Sgabeblack@google.com
196812854Sgabeblack@google.com                int n_bits = params.n_bits();
196912854Sgabeblack@google.com
197012854Sgabeblack@google.com                if (n_bits == 0) {
197112854Sgabeblack@google.com                    scfx_index x4 = calc_indices(params.iwl());
197212854Sgabeblack@google.com
197312854Sgabeblack@google.com                    if (x4.wi() >= size())
197412854Sgabeblack@google.com                        resize_to(x4.wi() + 1, 1);
197512854Sgabeblack@google.com
197612854Sgabeblack@google.com                    toggle_tc();
197712854Sgabeblack@google.com                    if (o_bit_at(x4) != o_bit_at(x))
197812854Sgabeblack@google.com                        o_invert(x2);
197912854Sgabeblack@google.com                    o_extend(x, SC_TC_);
198012854Sgabeblack@google.com                    toggle_tc();
198112854Sgabeblack@google.com                } else if (n_bits == 1) {
198212854Sgabeblack@google.com                    toggle_tc();
198312854Sgabeblack@google.com                    if (is_neg() != o_bit_at(x))
198412854Sgabeblack@google.com                        o_invert(x2);
198512854Sgabeblack@google.com                    o_extend(x, SC_TC_);
198612854Sgabeblack@google.com                    toggle_tc();
198712854Sgabeblack@google.com                } else if (n_bits < params.wl()) {
198812854Sgabeblack@google.com                    scfx_index x3 = calc_indices(params.iwl() - 1 - n_bits);
198912854Sgabeblack@google.com                    scfx_index x4 = calc_indices(params.iwl() - n_bits);
199012854Sgabeblack@google.com
199112854Sgabeblack@google.com                    // wrap-around least significant 'wl - n_bits' bits;
199212854Sgabeblack@google.com                    // saturate most significant 'n_bits' bits
199312854Sgabeblack@google.com                    toggle_tc();
199412854Sgabeblack@google.com                    if (is_neg() == o_bit_at(x4))
199512854Sgabeblack@google.com                        o_invert(x2);
199612854Sgabeblack@google.com                    o_set(x, x3, SC_TC_, under);
199712854Sgabeblack@google.com                    o_extend(x, SC_TC_);
199812854Sgabeblack@google.com                    toggle_tc();
199912854Sgabeblack@google.com                } else {
200012854Sgabeblack@google.com                    if (under)
200112854Sgabeblack@google.com                        o_set_low(x, SC_TC_);
200212854Sgabeblack@google.com                    else
200312854Sgabeblack@google.com                        o_set_high(x, x2, SC_TC_);
200412854Sgabeblack@google.com                }
200512854Sgabeblack@google.com                break;
200612854Sgabeblack@google.com            }
200712854Sgabeblack@google.com          default:
200812854Sgabeblack@google.com            ;
200912854Sgabeblack@google.com        }
201012854Sgabeblack@google.com
201112854Sgabeblack@google.com        find_sw();
201212854Sgabeblack@google.com    }
201312854Sgabeblack@google.com}
201412854Sgabeblack@google.com
201512854Sgabeblack@google.com
201612854Sgabeblack@google.com// ----------------------------------------------------------------------------
201712854Sgabeblack@google.com//  PUBLIC METHOD : cast
201812854Sgabeblack@google.com//
201912854Sgabeblack@google.com//  Performs a destructive cast operation on a scfx_rep.
202012854Sgabeblack@google.com// ----------------------------------------------------------------------------
202112854Sgabeblack@google.com
202212854Sgabeblack@google.comvoid
202312854Sgabeblack@google.comscfx_rep::cast(const scfx_params &params, bool &q_flag, bool &o_flag)
202412854Sgabeblack@google.com{
202512854Sgabeblack@google.com    q_flag = false;
202612854Sgabeblack@google.com    o_flag = false;
202712854Sgabeblack@google.com
202812854Sgabeblack@google.com    // check for special cases
202912854Sgabeblack@google.com    if (is_zero()) {
203012854Sgabeblack@google.com        if (is_neg())
203112854Sgabeblack@google.com            m_sign = 1;
203212854Sgabeblack@google.com        return;
203312854Sgabeblack@google.com    }
203412854Sgabeblack@google.com
203512854Sgabeblack@google.com    // perform casting
203612854Sgabeblack@google.com    quantization(params, q_flag);
203712854Sgabeblack@google.com    overflow(params, o_flag);
203812854Sgabeblack@google.com
203912854Sgabeblack@google.com    // check for special case: -0
204012854Sgabeblack@google.com    if (is_zero() && is_neg())
204112854Sgabeblack@google.com        m_sign = 1;
204212854Sgabeblack@google.com}
204312854Sgabeblack@google.com
204412854Sgabeblack@google.com
204512854Sgabeblack@google.com// ----------------------------------------------------------------------------
204612854Sgabeblack@google.com//  make sure, the two mantissas are aligned
204712854Sgabeblack@google.com// ----------------------------------------------------------------------------
204812854Sgabeblack@google.com
204912854Sgabeblack@google.comvoid
205012854Sgabeblack@google.comalign(const scfx_rep &lhs, const scfx_rep &rhs, int &new_wp,
205112854Sgabeblack@google.com      int &len_mant, scfx_mant_ref &lhs_mant, scfx_mant_ref &rhs_mant)
205212854Sgabeblack@google.com{
205312854Sgabeblack@google.com    bool need_lhs = true;
205412854Sgabeblack@google.com    bool need_rhs = true;
205512854Sgabeblack@google.com
205612854Sgabeblack@google.com    if (lhs.m_wp != rhs.m_wp || lhs.size() != rhs.size()) {
205712854Sgabeblack@google.com        int lower_bound_lhs = lhs.m_lsw - lhs.m_wp;
205812854Sgabeblack@google.com        int upper_bound_lhs = lhs.m_msw - lhs.m_wp;
205912854Sgabeblack@google.com        int lower_bound_rhs = rhs.m_lsw - rhs.m_wp;
206012854Sgabeblack@google.com        int upper_bound_rhs = rhs.m_msw - rhs.m_wp;
206112854Sgabeblack@google.com
206212854Sgabeblack@google.com        int lower_bound = sc_min(lower_bound_lhs, lower_bound_rhs);
206312854Sgabeblack@google.com        int upper_bound = sc_max(upper_bound_lhs, upper_bound_rhs);
206412854Sgabeblack@google.com
206512854Sgabeblack@google.com        new_wp = -lower_bound;
206612854Sgabeblack@google.com        len_mant = sc_max(min_mant, upper_bound - lower_bound + 1);
206712854Sgabeblack@google.com
206812854Sgabeblack@google.com        if (new_wp != lhs.m_wp || len_mant != lhs.size()) {
206912854Sgabeblack@google.com            lhs_mant = lhs.resize(len_mant, new_wp);
207012854Sgabeblack@google.com            need_lhs = false;
207112854Sgabeblack@google.com        }
207212854Sgabeblack@google.com
207312854Sgabeblack@google.com        if (new_wp != rhs.m_wp || len_mant != rhs.size()) {
207412854Sgabeblack@google.com            rhs_mant = rhs.resize(len_mant, new_wp);
207512854Sgabeblack@google.com            need_rhs = false;
207612854Sgabeblack@google.com        }
207712854Sgabeblack@google.com    }
207812854Sgabeblack@google.com
207912854Sgabeblack@google.com    if (need_lhs) {
208012854Sgabeblack@google.com        lhs_mant = lhs.m_mant;
208112854Sgabeblack@google.com    }
208212854Sgabeblack@google.com
208312854Sgabeblack@google.com    if (need_rhs) {
208412854Sgabeblack@google.com        rhs_mant = rhs.m_mant;
208512854Sgabeblack@google.com    }
208612854Sgabeblack@google.com}
208712854Sgabeblack@google.com
208812854Sgabeblack@google.com
208912854Sgabeblack@google.com// ----------------------------------------------------------------------------
209012854Sgabeblack@google.com//  compare two mantissas
209112854Sgabeblack@google.com// ----------------------------------------------------------------------------
209212854Sgabeblack@google.com
209312854Sgabeblack@google.comint
209412854Sgabeblack@google.comcompare_msw_ff(const scfx_rep &lhs, const scfx_rep &rhs)
209512854Sgabeblack@google.com{
209612854Sgabeblack@google.com    // special case: rhs.m_mant[rhs.m_msw + 1] == 1
209712854Sgabeblack@google.com    if (rhs.m_msw < rhs.size() - 1 && rhs.m_mant[rhs.m_msw + 1 ] != 0) {
209812854Sgabeblack@google.com        return -1;
209912854Sgabeblack@google.com    }
210012854Sgabeblack@google.com
210112854Sgabeblack@google.com    int lhs_size = lhs.m_msw - lhs.m_lsw + 1;
210212854Sgabeblack@google.com    int rhs_size = rhs.m_msw - rhs.m_lsw + 1;
210312854Sgabeblack@google.com
210412854Sgabeblack@google.com    int size = sc_min(lhs_size, rhs_size);
210512854Sgabeblack@google.com
210612854Sgabeblack@google.com    int lhs_index = lhs.m_msw;
210712854Sgabeblack@google.com    int rhs_index = rhs.m_msw;
210812854Sgabeblack@google.com
210912854Sgabeblack@google.com    int i;
211012854Sgabeblack@google.com
211112854Sgabeblack@google.com    for (i = 0;
211212854Sgabeblack@google.com         i < size && lhs.m_mant[lhs_index] == rhs.m_mant[rhs_index];
211312854Sgabeblack@google.com         i++) {
211412854Sgabeblack@google.com        lhs_index--;
211512854Sgabeblack@google.com        rhs_index--;
211612854Sgabeblack@google.com    }
211712854Sgabeblack@google.com
211812854Sgabeblack@google.com    if (i == size) {
211912854Sgabeblack@google.com        if (lhs_size == rhs_size) {
212012854Sgabeblack@google.com            return 0;
212112854Sgabeblack@google.com        }
212212854Sgabeblack@google.com
212312854Sgabeblack@google.com        if (lhs_size < rhs_size) {
212412854Sgabeblack@google.com            return -1;
212512854Sgabeblack@google.com        } else {
212612854Sgabeblack@google.com            return 1;
212712854Sgabeblack@google.com        }
212812854Sgabeblack@google.com    }
212912854Sgabeblack@google.com
213012854Sgabeblack@google.com    if (lhs.m_mant[lhs_index] < rhs.m_mant[rhs_index]) {
213112854Sgabeblack@google.com        return -1;
213212854Sgabeblack@google.com    } else {
213312854Sgabeblack@google.com        return 1;
213412854Sgabeblack@google.com    }
213512854Sgabeblack@google.com}
213612854Sgabeblack@google.com
213712854Sgabeblack@google.com
213812854Sgabeblack@google.com// ----------------------------------------------------------------------------
213912854Sgabeblack@google.com//  divide the mantissa by ten
214012854Sgabeblack@google.com// ----------------------------------------------------------------------------
214112854Sgabeblack@google.com
214212854Sgabeblack@google.comunsigned int
214312854Sgabeblack@google.comscfx_rep::divide_by_ten()
214412854Sgabeblack@google.com{
214512854Sgabeblack@google.com#if defined(SC_BOOST_BIG_ENDIAN)
214612854Sgabeblack@google.com    half_word *hw = (half_word *)&m_mant[m_msw];
214712854Sgabeblack@google.com#elif defined(SC_BOOST_LITTLE_ENDIAN)
214812854Sgabeblack@google.com    half_word *hw = ((half_word *)&m_mant[m_msw]) + 1;
214912854Sgabeblack@google.com#endif
215012854Sgabeblack@google.com
215112854Sgabeblack@google.com    unsigned int remainder = 0;
215212854Sgabeblack@google.com
215312854Sgabeblack@google.com    word_short ls;
215412854Sgabeblack@google.com    ls.l = 0;
215512854Sgabeblack@google.com
215612854Sgabeblack@google.com#if defined(SC_BOOST_BIG_ENDIAN)
215712854Sgabeblack@google.com    for (int i = 0, end = (m_msw - m_wp + 1) * 2; i < end; i++) {
215812854Sgabeblack@google.com#elif defined(SC_BOOST_LITTLE_ENDIAN)
215912854Sgabeblack@google.com    for (int i = 0, end = -(m_msw - m_wp + 1) * 2; i > end; i--) {
216012854Sgabeblack@google.com#endif
216112854Sgabeblack@google.com        ls.s.u = static_cast<half_word>(remainder);
216212854Sgabeblack@google.com        ls.s.l = hw[i];
216312854Sgabeblack@google.com        remainder = ls.l % 10;
216412854Sgabeblack@google.com        ls.l /= 10;
216512854Sgabeblack@google.com        hw[i] = ls.s.l;
216612854Sgabeblack@google.com    }
216712854Sgabeblack@google.com
216812854Sgabeblack@google.com    return remainder;
216912854Sgabeblack@google.com}
217012854Sgabeblack@google.com
217112854Sgabeblack@google.com
217212854Sgabeblack@google.com// ----------------------------------------------------------------------------
217312854Sgabeblack@google.com//  multiply the mantissa by ten
217412854Sgabeblack@google.com// ----------------------------------------------------------------------------
217512854Sgabeblack@google.com
217612854Sgabeblack@google.comvoid
217712854Sgabeblack@google.comscfx_rep::multiply_by_ten()
217812854Sgabeblack@google.com{
217912854Sgabeblack@google.com    int size = m_mant.size() + 1;
218012854Sgabeblack@google.com
218112854Sgabeblack@google.com    scfx_mant mant8(size);
218212854Sgabeblack@google.com    scfx_mant mant2(size);
218312854Sgabeblack@google.com
218412854Sgabeblack@google.com    size--;
218512854Sgabeblack@google.com
218612854Sgabeblack@google.com    mant8[size] = (m_mant[size - 1] >> (bits_in_word - 3));
218712854Sgabeblack@google.com    mant2[size] = (m_mant[size - 1] >> (bits_in_word - 1));
218812854Sgabeblack@google.com
218912854Sgabeblack@google.com    while (--size) {
219012854Sgabeblack@google.com        mant8[size] = (m_mant[size] << 3) |
219112854Sgabeblack@google.com                      (m_mant[size - 1] >> (bits_in_word - 3));
219212854Sgabeblack@google.com        mant2[size] = (m_mant[size] << 1) |
219312854Sgabeblack@google.com                      (m_mant[size - 1] >> (bits_in_word - 1));
219412854Sgabeblack@google.com    }
219512854Sgabeblack@google.com
219612854Sgabeblack@google.com    mant8[0] = (m_mant[0] << 3);
219712854Sgabeblack@google.com    mant2[0] = (m_mant[0] << 1);
219812854Sgabeblack@google.com
219912854Sgabeblack@google.com    add_mants(m_mant.size(), m_mant, mant8, mant2);
220012854Sgabeblack@google.com}
220112854Sgabeblack@google.com
220212854Sgabeblack@google.com
220312854Sgabeblack@google.com// ----------------------------------------------------------------------------
220412854Sgabeblack@google.com//  normalize
220512854Sgabeblack@google.com// ----------------------------------------------------------------------------
220612854Sgabeblack@google.com
220712854Sgabeblack@google.comvoid
220812854Sgabeblack@google.comscfx_rep::normalize(int exponent)
220912854Sgabeblack@google.com{
221012854Sgabeblack@google.com    int shift = exponent % bits_in_word;
221112854Sgabeblack@google.com    if (shift < 0) {
221212854Sgabeblack@google.com        shift += bits_in_word;
221312854Sgabeblack@google.com    }
221412854Sgabeblack@google.com
221512854Sgabeblack@google.com    if (shift) {
221612854Sgabeblack@google.com        shift_left(shift);
221712854Sgabeblack@google.com    }
221812854Sgabeblack@google.com
221912854Sgabeblack@google.com    find_sw();
222012854Sgabeblack@google.com
222112854Sgabeblack@google.com    m_wp = (shift - exponent) / bits_in_word;
222212854Sgabeblack@google.com}
222312854Sgabeblack@google.com
222412854Sgabeblack@google.com
222512854Sgabeblack@google.com// ----------------------------------------------------------------------------
222612854Sgabeblack@google.com//  return a new mantissa that is aligned and resized
222712854Sgabeblack@google.com// ----------------------------------------------------------------------------
222812854Sgabeblack@google.com
222912854Sgabeblack@google.comscfx_mant *
223012854Sgabeblack@google.comscfx_rep::resize(int new_size, int new_wp) const
223112854Sgabeblack@google.com{
223212854Sgabeblack@google.com    scfx_mant *result = new scfx_mant(new_size);
223312854Sgabeblack@google.com
223412854Sgabeblack@google.com    result->clear();
223512854Sgabeblack@google.com
223612854Sgabeblack@google.com    int shift = new_wp - m_wp;
223712854Sgabeblack@google.com
223812854Sgabeblack@google.com    for (int j = m_lsw; j <= m_msw; j++) {
223912854Sgabeblack@google.com        (*result)[j + shift] = m_mant[j];
224012854Sgabeblack@google.com    }
224112854Sgabeblack@google.com
224212854Sgabeblack@google.com    return result;
224312854Sgabeblack@google.com}
224412854Sgabeblack@google.com
224512854Sgabeblack@google.com
224612854Sgabeblack@google.com// ----------------------------------------------------------------------------
224712854Sgabeblack@google.com//  set a single bit
224812854Sgabeblack@google.com// ----------------------------------------------------------------------------
224912854Sgabeblack@google.com
225012854Sgabeblack@google.comvoid
225112854Sgabeblack@google.comscfx_rep::set_bin(int i)
225212854Sgabeblack@google.com{
225312854Sgabeblack@google.com    m_mant[i >> 5] |= 1 << (i & 31);
225412854Sgabeblack@google.com}
225512854Sgabeblack@google.com
225612854Sgabeblack@google.com
225712854Sgabeblack@google.com// ----------------------------------------------------------------------------
225812854Sgabeblack@google.com//  set three bits
225912854Sgabeblack@google.com// ----------------------------------------------------------------------------
226012854Sgabeblack@google.com
226112854Sgabeblack@google.comvoid
226212854Sgabeblack@google.comscfx_rep::set_oct(int i, int n)
226312854Sgabeblack@google.com{
226412854Sgabeblack@google.com    if (n & 1) {
226512854Sgabeblack@google.com        m_mant[i >> 5] |= 1 << (i & 31);
226612854Sgabeblack@google.com    }
226712854Sgabeblack@google.com    i++;
226812854Sgabeblack@google.com    if (n & 2) {
226912854Sgabeblack@google.com        m_mant[i >> 5] |= 1 << (i & 31);
227012854Sgabeblack@google.com    }
227112854Sgabeblack@google.com    i++;
227212854Sgabeblack@google.com    if (n & 4) {
227312854Sgabeblack@google.com        m_mant[i >> 5] |= 1 << (i & 31);
227412854Sgabeblack@google.com    }
227512854Sgabeblack@google.com}
227612854Sgabeblack@google.com
227712854Sgabeblack@google.com
227812854Sgabeblack@google.com// ----------------------------------------------------------------------------
227912854Sgabeblack@google.com//  set four bits
228012854Sgabeblack@google.com// ----------------------------------------------------------------------------
228112854Sgabeblack@google.com
228212854Sgabeblack@google.comvoid
228312854Sgabeblack@google.comscfx_rep::set_hex(int i, int n)
228412854Sgabeblack@google.com{
228512854Sgabeblack@google.com    if (n & 1) {
228612854Sgabeblack@google.com        m_mant[i >> 5] |= 1 << (i & 31);
228712854Sgabeblack@google.com    }
228812854Sgabeblack@google.com    i++;
228912854Sgabeblack@google.com    if (n & 2) {
229012854Sgabeblack@google.com        m_mant[i >> 5] |= 1 << (i & 31);
229112854Sgabeblack@google.com    }
229212854Sgabeblack@google.com    i++;
229312854Sgabeblack@google.com    if (n & 4) {
229412854Sgabeblack@google.com        m_mant[i >> 5] |= 1 << (i & 31);
229512854Sgabeblack@google.com    }
229612854Sgabeblack@google.com    i++;
229712854Sgabeblack@google.com    if (n & 8) {
229812854Sgabeblack@google.com        m_mant[i >> 5] |= 1 << (i & 31);
229912854Sgabeblack@google.com    }
230012854Sgabeblack@google.com}
230112854Sgabeblack@google.com
230212854Sgabeblack@google.com
230312854Sgabeblack@google.com// ----------------------------------------------------------------------------
230412854Sgabeblack@google.com//  PRIVATE METHOD : shift_left
230512854Sgabeblack@google.com//
230612854Sgabeblack@google.com//  Shifts a scfx_rep to the left by a MAXIMUM of bits_in_word - 1 bits.
230712854Sgabeblack@google.com// ----------------------------------------------------------------------------
230812854Sgabeblack@google.com
230912854Sgabeblack@google.comvoid
231012854Sgabeblack@google.comscfx_rep::shift_left(int n)
231112854Sgabeblack@google.com{
231212854Sgabeblack@google.com    if (n != 0) {
231312854Sgabeblack@google.com        int shift_left = n;
231412854Sgabeblack@google.com        int shift_right = bits_in_word - n;
231512854Sgabeblack@google.com
231612854Sgabeblack@google.com        SC_ASSERT_(!(m_mant[size() - 1] >> shift_right),
231712854Sgabeblack@google.com                   "shift_left overflow");
231812854Sgabeblack@google.com
231912854Sgabeblack@google.com        for (int i = size() - 1; i > 0; i--) {
232012854Sgabeblack@google.com            m_mant[i] = (m_mant[i] << shift_left) |
232112854Sgabeblack@google.com                        (m_mant[i - 1] >> shift_right);
232212854Sgabeblack@google.com        }
232312854Sgabeblack@google.com        m_mant[0] <<= shift_left;
232412854Sgabeblack@google.com    }
232512854Sgabeblack@google.com}
232612854Sgabeblack@google.com
232712854Sgabeblack@google.com
232812854Sgabeblack@google.com// ----------------------------------------------------------------------------
232912854Sgabeblack@google.com//  PRIVATE METHOD : shift_right
233012854Sgabeblack@google.com//
233112854Sgabeblack@google.com//  Shifts a scfx_rep to the right by a MAXIMUM of bits_in_word - 1 bits.
233212854Sgabeblack@google.com// ----------------------------------------------------------------------------
233312854Sgabeblack@google.com
233412854Sgabeblack@google.comvoid
233512854Sgabeblack@google.comscfx_rep::shift_right(int n)
233612854Sgabeblack@google.com{
233712854Sgabeblack@google.com    if (n != 0) {
233812854Sgabeblack@google.com        int shift_left = bits_in_word - n;
233912854Sgabeblack@google.com        int shift_right = n;
234012854Sgabeblack@google.com
234112854Sgabeblack@google.com        SC_ASSERT_(!(m_mant[0] << shift_left), "shift_right overflow");
234212854Sgabeblack@google.com
234312854Sgabeblack@google.com        for (int i = 0; i < size() - 1; i++) {
234412854Sgabeblack@google.com            m_mant[i] = (m_mant[i] >> shift_right) |
234512854Sgabeblack@google.com                        (m_mant[i + 1] << shift_left);
234612854Sgabeblack@google.com        }
234712854Sgabeblack@google.com        m_mant[size() - 1] >>= shift_right;
234812854Sgabeblack@google.com    }
234912854Sgabeblack@google.com}
235012854Sgabeblack@google.com
235112854Sgabeblack@google.com
235212854Sgabeblack@google.com// ----------------------------------------------------------------------------
235312854Sgabeblack@google.com//  METHOD : get_bit
235412854Sgabeblack@google.com//
235512854Sgabeblack@google.com//  Tests a bit, in two's complement.
235612854Sgabeblack@google.com// ----------------------------------------------------------------------------
235712854Sgabeblack@google.com
235812854Sgabeblack@google.combool
235912854Sgabeblack@google.comscfx_rep::get_bit(int i) const
236012854Sgabeblack@google.com{
236112854Sgabeblack@google.com    if (!is_normal())
236212854Sgabeblack@google.com        return false;
236312854Sgabeblack@google.com
236412854Sgabeblack@google.com    scfx_index x = calc_indices(i);
236512854Sgabeblack@google.com
236612854Sgabeblack@google.com    if (x.wi() >= size())
236712854Sgabeblack@google.com        return is_neg();
236812854Sgabeblack@google.com
236912854Sgabeblack@google.com    if (x.wi() < 0)
237012854Sgabeblack@google.com        return false;
237112854Sgabeblack@google.com
237212854Sgabeblack@google.com    const_cast<scfx_rep*>(this)->toggle_tc();
237312854Sgabeblack@google.com
237412854Sgabeblack@google.com    bool result = (m_mant[x.wi()] & (1 << x.bi())) != 0;
237512854Sgabeblack@google.com
237612854Sgabeblack@google.com    const_cast<scfx_rep *>(this)->toggle_tc();
237712854Sgabeblack@google.com
237812854Sgabeblack@google.com    return result;
237912854Sgabeblack@google.com}
238012854Sgabeblack@google.com
238112854Sgabeblack@google.com
238212854Sgabeblack@google.com// ----------------------------------------------------------------------------
238312854Sgabeblack@google.com//  METHOD : set
238412854Sgabeblack@google.com//
238512854Sgabeblack@google.com//  Sets a bit, in two's complement, between iwl-1 and -fwl.
238612854Sgabeblack@google.com// ----------------------------------------------------------------------------
238712854Sgabeblack@google.com
238812854Sgabeblack@google.combool
238912854Sgabeblack@google.comscfx_rep::set(int i, const scfx_params &params)
239012854Sgabeblack@google.com{
239112854Sgabeblack@google.com    if (!is_normal())
239212854Sgabeblack@google.com        return false;
239312854Sgabeblack@google.com
239412854Sgabeblack@google.com    scfx_index x = calc_indices(i);
239512854Sgabeblack@google.com
239612854Sgabeblack@google.com    if (x.wi() >= size()) {
239712854Sgabeblack@google.com        if (is_neg())
239812854Sgabeblack@google.com            return true;
239912854Sgabeblack@google.com        else
240012854Sgabeblack@google.com            resize_to(x.wi() + 1, 1);
240112854Sgabeblack@google.com    } else if (x.wi() < 0) {
240212854Sgabeblack@google.com        resize_to(size() - x.wi(), -1);
240312854Sgabeblack@google.com        x.wi(0);
240412854Sgabeblack@google.com    }
240512854Sgabeblack@google.com
240612854Sgabeblack@google.com    toggle_tc();
240712854Sgabeblack@google.com
240812854Sgabeblack@google.com    m_mant[x.wi()] |= 1 << x.bi();
240912854Sgabeblack@google.com
241012854Sgabeblack@google.com    if (i == params.iwl() - 1)
241112854Sgabeblack@google.com        o_extend(x, params.enc()); // sign extension
241212854Sgabeblack@google.com
241312854Sgabeblack@google.com    toggle_tc();
241412854Sgabeblack@google.com
241512854Sgabeblack@google.com    find_sw();
241612854Sgabeblack@google.com
241712854Sgabeblack@google.com    return true;
241812854Sgabeblack@google.com}
241912854Sgabeblack@google.com
242012854Sgabeblack@google.com
242112854Sgabeblack@google.com// ----------------------------------------------------------------------------
242212854Sgabeblack@google.com//  METHOD : clear
242312854Sgabeblack@google.com//
242412854Sgabeblack@google.com//  Clears a bit, in two's complement, between iwl-1 and -fwl.
242512854Sgabeblack@google.com// ----------------------------------------------------------------------------
242612854Sgabeblack@google.com
242712854Sgabeblack@google.combool
242812854Sgabeblack@google.comscfx_rep::clear(int i, const scfx_params &params)
242912854Sgabeblack@google.com{
243012854Sgabeblack@google.com    if (!is_normal())
243112854Sgabeblack@google.com        return false;
243212854Sgabeblack@google.com
243312854Sgabeblack@google.com    scfx_index x = calc_indices(i);
243412854Sgabeblack@google.com
243512854Sgabeblack@google.com    if (x.wi() >= size()) {
243612854Sgabeblack@google.com        if (!is_neg())
243712854Sgabeblack@google.com            return true;
243812854Sgabeblack@google.com        else
243912854Sgabeblack@google.com            resize_to(x.wi() + 1, 1);
244012854Sgabeblack@google.com    } else if (x.wi() < 0) {
244112854Sgabeblack@google.com        return true;
244212854Sgabeblack@google.com    }
244312854Sgabeblack@google.com
244412854Sgabeblack@google.com    toggle_tc();
244512854Sgabeblack@google.com
244612854Sgabeblack@google.com    m_mant[x.wi()] &= ~(1 << x.bi());
244712854Sgabeblack@google.com
244812854Sgabeblack@google.com    if (i == params.iwl() - 1)
244912854Sgabeblack@google.com        o_extend(x, params.enc()); // sign extension
245012854Sgabeblack@google.com
245112854Sgabeblack@google.com    toggle_tc();
245212854Sgabeblack@google.com
245312854Sgabeblack@google.com    find_sw();
245412854Sgabeblack@google.com
245512854Sgabeblack@google.com    return true;
245612854Sgabeblack@google.com}
245712854Sgabeblack@google.com
245812854Sgabeblack@google.com
245912854Sgabeblack@google.com// ----------------------------------------------------------------------------
246012854Sgabeblack@google.com//  METHOD : get_slice
246112854Sgabeblack@google.com// ----------------------------------------------------------------------------
246212854Sgabeblack@google.com
246312854Sgabeblack@google.combool
246412854Sgabeblack@google.comscfx_rep::get_slice(int i, int j, const scfx_params &, sc_bv_base &bv) const
246512854Sgabeblack@google.com{
246612854Sgabeblack@google.com    if (is_nan() || is_inf())
246712854Sgabeblack@google.com        return false;
246812854Sgabeblack@google.com
246912854Sgabeblack@google.com    // get the bits
247012854Sgabeblack@google.com
247112854Sgabeblack@google.com    int l = j;
247212854Sgabeblack@google.com    for (int k = 0; k < bv.length(); ++k) {
247312854Sgabeblack@google.com        bv[k] = get_bit(l);
247412854Sgabeblack@google.com
247512854Sgabeblack@google.com        if (i >= j)
247612854Sgabeblack@google.com            ++l;
247712854Sgabeblack@google.com        else
247812854Sgabeblack@google.com            --l;
247912854Sgabeblack@google.com    }
248012854Sgabeblack@google.com
248112854Sgabeblack@google.com    return true;
248212854Sgabeblack@google.com}
248312854Sgabeblack@google.com
248412854Sgabeblack@google.combool
248512854Sgabeblack@google.comscfx_rep::set_slice(int i, int j, const scfx_params &params,
248612854Sgabeblack@google.com                    const sc_bv_base &bv)
248712854Sgabeblack@google.com{
248812854Sgabeblack@google.com    if (is_nan() || is_inf())
248912854Sgabeblack@google.com        return false;
249012854Sgabeblack@google.com
249112854Sgabeblack@google.com    // set the bits
249212854Sgabeblack@google.com    int l = j;
249312854Sgabeblack@google.com    for (int k = 0; k < bv.length(); ++k) {
249412854Sgabeblack@google.com        if (bv[k].to_bool())
249512854Sgabeblack@google.com            set(l, params);
249612854Sgabeblack@google.com        else
249712854Sgabeblack@google.com            clear(l, params);
249812854Sgabeblack@google.com
249912854Sgabeblack@google.com        if (i >= j)
250012854Sgabeblack@google.com            ++l;
250112854Sgabeblack@google.com        else
250212854Sgabeblack@google.com            --l;
250312854Sgabeblack@google.com    }
250412854Sgabeblack@google.com
250512854Sgabeblack@google.com    return true;
250612854Sgabeblack@google.com}
250712854Sgabeblack@google.com
250812854Sgabeblack@google.com
250912854Sgabeblack@google.com// ----------------------------------------------------------------------------
251012854Sgabeblack@google.com//  METHOD : print
251112854Sgabeblack@google.com// ----------------------------------------------------------------------------
251212854Sgabeblack@google.com
251312854Sgabeblack@google.comvoid
251412854Sgabeblack@google.comscfx_rep::print(::std::ostream &os) const
251512854Sgabeblack@google.com{
251612854Sgabeblack@google.com    os << to_string(SC_DEC, -1, SC_E);
251712854Sgabeblack@google.com}
251812854Sgabeblack@google.com
251912854Sgabeblack@google.com
252012854Sgabeblack@google.com// ----------------------------------------------------------------------------
252112854Sgabeblack@google.com//  METHOD : dump
252212854Sgabeblack@google.com// ----------------------------------------------------------------------------
252312854Sgabeblack@google.com
252412854Sgabeblack@google.comvoid
252512854Sgabeblack@google.comscfx_rep::dump(::std::ostream &os) const
252612854Sgabeblack@google.com{
252712854Sgabeblack@google.com    os << "scfx_rep" << ::std::endl;
252812854Sgabeblack@google.com    os << "(" << ::std::endl;
252912854Sgabeblack@google.com
253012854Sgabeblack@google.com    os << "mant  =" << ::std::endl;
253112854Sgabeblack@google.com    for (int i = size() - 1; i >= 0; i--) {
253212854Sgabeblack@google.com        char buf[BUFSIZ];
253312854Sgabeblack@google.com        std::sprintf(buf, " %d: %10u (%8x)", i,
253412854Sgabeblack@google.com                     (int)m_mant[i], (int)m_mant[i]);
253512854Sgabeblack@google.com        os << buf << ::std::endl;
253612854Sgabeblack@google.com    }
253712854Sgabeblack@google.com
253812854Sgabeblack@google.com    os << "wp = " << m_wp << ::std::endl;
253912854Sgabeblack@google.com    os << "sign = " << m_sign << ::std::endl;
254012854Sgabeblack@google.com
254112854Sgabeblack@google.com    os << "state = ";
254212854Sgabeblack@google.com    switch (m_state) {
254312854Sgabeblack@google.com      case normal:
254412854Sgabeblack@google.com        os << "normal";
254512854Sgabeblack@google.com        break;
254612854Sgabeblack@google.com      case infinity:
254712854Sgabeblack@google.com        os << "infinity";
254812854Sgabeblack@google.com        break;
254912854Sgabeblack@google.com      case not_a_number:
255012854Sgabeblack@google.com        os << "not_a_number";
255112854Sgabeblack@google.com        break;
255212854Sgabeblack@google.com      default:
255312854Sgabeblack@google.com        os << "unknown";
255412854Sgabeblack@google.com    }
255512854Sgabeblack@google.com    os << ::std::endl;
255612854Sgabeblack@google.com
255712854Sgabeblack@google.com    os << "msw = " << m_msw << ::std::endl;
255812854Sgabeblack@google.com    os << "lsw = " << m_lsw << ::std::endl;
255912854Sgabeblack@google.com
256012854Sgabeblack@google.com    os << ")" << ::std::endl;
256112854Sgabeblack@google.com}
256212854Sgabeblack@google.com
256312854Sgabeblack@google.com
256412854Sgabeblack@google.com// ----------------------------------------------------------------------------
256512854Sgabeblack@google.com//  METHOD : get_type
256612854Sgabeblack@google.com// ----------------------------------------------------------------------------
256712854Sgabeblack@google.com
256812854Sgabeblack@google.comvoid
256912854Sgabeblack@google.comscfx_rep::get_type(int &wl, int &iwl, sc_enc &enc) const
257012854Sgabeblack@google.com{
257112854Sgabeblack@google.com    if (is_nan() || is_inf()) {
257212854Sgabeblack@google.com        wl  = 0;
257312854Sgabeblack@google.com        iwl = 0;
257412854Sgabeblack@google.com        enc = SC_TC_;
257512854Sgabeblack@google.com        return;
257612854Sgabeblack@google.com    }
257712854Sgabeblack@google.com
257812854Sgabeblack@google.com    if (is_zero()) {
257912854Sgabeblack@google.com        wl  = 1;
258012854Sgabeblack@google.com        iwl = 1;
258112854Sgabeblack@google.com        enc = SC_US_;
258212854Sgabeblack@google.com        return;
258312854Sgabeblack@google.com    }
258412854Sgabeblack@google.com
258512854Sgabeblack@google.com    int msb = (m_msw - m_wp) * bits_in_word +
258612854Sgabeblack@google.com              scfx_find_msb(m_mant[ m_msw ]) + 1;
258712854Sgabeblack@google.com    while (get_bit(msb) == get_bit(msb - 1)) {
258812854Sgabeblack@google.com        --msb;
258912854Sgabeblack@google.com    }
259012854Sgabeblack@google.com
259112854Sgabeblack@google.com    int lsb = (m_lsw - m_wp) * bits_in_word +
259212854Sgabeblack@google.com              scfx_find_lsb(m_mant[m_lsw]);
259312854Sgabeblack@google.com
259412854Sgabeblack@google.com    if (is_neg()) {
259512854Sgabeblack@google.com        wl  = msb - lsb + 1;
259612854Sgabeblack@google.com        iwl = msb + 1;
259712854Sgabeblack@google.com        enc = SC_TC_;
259812854Sgabeblack@google.com    } else {
259912854Sgabeblack@google.com        wl  = msb - lsb;
260012854Sgabeblack@google.com        iwl = msb;
260112854Sgabeblack@google.com        enc = SC_US_;
260212854Sgabeblack@google.com    }
260312854Sgabeblack@google.com}
260412854Sgabeblack@google.com
260512854Sgabeblack@google.com
260612854Sgabeblack@google.com// ----------------------------------------------------------------------------
260712854Sgabeblack@google.com//  PRIVATE METHOD : round
260812854Sgabeblack@google.com//
260912854Sgabeblack@google.com//  Performs convergent rounding (rounding to even) as in floating-point.
261012854Sgabeblack@google.com// ----------------------------------------------------------------------------
261112854Sgabeblack@google.com
261212854Sgabeblack@google.comvoid
261312854Sgabeblack@google.comscfx_rep::round(int wl)
261412854Sgabeblack@google.com{
261512854Sgabeblack@google.com    // check for special cases
261612854Sgabeblack@google.com
261712854Sgabeblack@google.com    if (is_nan() || is_inf() || is_zero())
261812854Sgabeblack@google.com        return;
261912854Sgabeblack@google.com
262012854Sgabeblack@google.com    // estimate effective wordlength and compare
262112854Sgabeblack@google.com    int wl_effective;
262212854Sgabeblack@google.com    wl_effective = (m_msw - m_lsw + 1) * bits_in_word;
262312854Sgabeblack@google.com    if (wl_effective <= wl)
262412854Sgabeblack@google.com        return;
262512854Sgabeblack@google.com
262612854Sgabeblack@google.com    // calculate effective wordlength and compare
262712854Sgabeblack@google.com    int msb = scfx_find_msb(m_mant[m_msw]);
262812854Sgabeblack@google.com    int lsb = scfx_find_lsb(m_mant[m_lsw]);
262912854Sgabeblack@google.com    wl_effective = (m_msw * bits_in_word + msb) -
263012854Sgabeblack@google.com                   (m_lsw * bits_in_word + lsb) + 1;
263112854Sgabeblack@google.com    if (wl_effective <= wl)
263212854Sgabeblack@google.com        return;
263312854Sgabeblack@google.com
263412854Sgabeblack@google.com    // perform rounding
263512854Sgabeblack@google.com    int wi = m_msw - (wl - 1) / bits_in_word;
263612854Sgabeblack@google.com    int bi = msb - (wl - 1) % bits_in_word;
263712854Sgabeblack@google.com    if (bi < 0) {
263812854Sgabeblack@google.com        --wi;
263912854Sgabeblack@google.com        bi += bits_in_word;
264012854Sgabeblack@google.com    }
264112854Sgabeblack@google.com
264212854Sgabeblack@google.com    scfx_index x(wi, bi);
264312854Sgabeblack@google.com
264412854Sgabeblack@google.com    if ((q_bit(x) && ! q_zero(x)) || (q_bit(x) && q_zero(x) && q_odd(x))) {
264512854Sgabeblack@google.com        q_incr(x);
264612854Sgabeblack@google.com    }
264712854Sgabeblack@google.com    q_clear(x);
264812854Sgabeblack@google.com
264912854Sgabeblack@google.com    find_sw();
265012854Sgabeblack@google.com
265112854Sgabeblack@google.com    m_r_flag = true;
265212854Sgabeblack@google.com}
265312854Sgabeblack@google.com
265412854Sgabeblack@google.com} // namespace sc_dt
2655