sc_fxval.cc revision 12854:c95c35407325
1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20/*****************************************************************************
21
22  sc_fxval.cpp -
23
24  Original Author: Martin Janssen, Synopsys, Inc.
25
26 *****************************************************************************/
27
28/*****************************************************************************
29
30  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
31  changes you are making here.
32
33      Name, Affiliation, Date:
34  Description of Modification:
35
36 *****************************************************************************/
37
38
39// $Log: sc_fxval.cpp,v $
40// Revision 1.1.1.1  2006/12/15 20:20:04  acg
41// SystemC 2.3
42//
43// Revision 1.3  2006/01/13 18:53:58  acg
44// Andy Goodrich: added $Log command so that CVS comments are reproduced in
45// the source.
46//
47
48#include <cctype>
49#include <cfloat>
50#include <cmath>
51#include <cstdlib>
52
53#include "systemc/ext/dt/fx/sc_fxval.hh"
54
55namespace sc_dt
56{
57
58// ----------------------------------------------------------------------------
59//  CLASS : sc_fxval
60//
61//  Fixed-point value type; arbitrary precision.
62// ----------------------------------------------------------------------------
63
64// explicit conversion to character string
65
66const std::string
67sc_fxval::to_string() const
68{
69    return std::string(m_rep->to_string(SC_DEC, -1, SC_E));
70}
71
72const std::string
73sc_fxval::to_string(sc_numrep numrep) const
74{
75    return std::string(m_rep->to_string(numrep, -1, SC_E));
76}
77
78const std::string
79sc_fxval::to_string(sc_numrep numrep, bool w_prefix) const
80{
81    return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), SC_E));
82}
83
84const std::string
85sc_fxval::to_string(sc_fmt fmt) const
86{
87    return std::string(m_rep->to_string(SC_DEC, -1, fmt));
88}
89
90const std::string
91sc_fxval::to_string(sc_numrep numrep, sc_fmt fmt) const
92{
93    return std::string(m_rep->to_string(numrep, -1, fmt));
94}
95
96const std::string
97sc_fxval::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const
98{
99    return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), fmt));
100}
101
102
103const std::string
104sc_fxval::to_dec() const
105{
106    return std::string(m_rep->to_string(SC_DEC, -1, SC_E));
107}
108
109const std::string
110sc_fxval::to_bin() const
111{
112    return std::string(m_rep->to_string(SC_BIN, -1, SC_E));
113}
114
115const std::string
116sc_fxval::to_oct() const
117{
118    return std::string(m_rep->to_string(SC_OCT, -1, SC_E));
119}
120
121const std::string
122sc_fxval::to_hex() const
123{
124    return std::string(m_rep->to_string(SC_HEX, -1, SC_E));
125}
126
127
128// print or dump content
129
130void sc_fxval::print(::std::ostream &os) const { m_rep->print(os); }
131
132void
133sc_fxval::scan(::std::istream &is)
134{
135    std::string s;
136    is >> s;
137    *this = s.c_str();
138}
139
140void
141sc_fxval::dump(::std::ostream &os) const
142{
143    os << "sc_fxval" << ::std::endl;
144    os << "(" << ::std::endl;
145    os << "rep = ";
146    m_rep->dump(os);
147    // TO BE COMPLETED
148    // os << "r_flag   = " << m_r_flag << ::std::endl;
149    // os << "observer = ";
150    // if (m_observer != 0)
151    //     m_observer->dump(os);
152    // else
153    //     os << "0" << ::std::endl;
154    os << ")" << ::std::endl;
155}
156
157// protected methods and friend functions
158sc_fxval_observer *
159sc_fxval::lock_observer() const
160{
161    SC_ASSERT_(m_observer != 0, "lock observer failed");
162    sc_fxval_observer *tmp = m_observer;
163    m_observer = 0;
164    return tmp;
165}
166
167void
168sc_fxval::unlock_observer(sc_fxval_observer *observer_) const
169{
170    SC_ASSERT_(observer_ != 0, "unlock observer failed");
171    m_observer = observer_;
172}
173
174
175// ----------------------------------------------------------------------------
176//  CLASS : sc_fxval_fast
177//
178//  Fixed-point value types; limited precision.
179// ----------------------------------------------------------------------------
180
181static void
182print_dec(scfx_string &s, scfx_ieee_double id, int w_prefix, sc_fmt fmt)
183{
184    if (id.negative() != 0) {
185        id.negative(0);
186        s += '-';
187    }
188
189    if (w_prefix == 1) {
190        scfx_print_prefix(s, SC_DEC);
191    }
192
193    if (id.is_zero()) {
194        s += '0';
195        return;
196    }
197
198    // split 'id' into its integer and fractional part
199    double int_part;
200    double frac_part = std::modf(static_cast<double>(id), &int_part);
201
202    int i;
203
204    // print integer part
205    int int_digits = 0;
206    int int_zeros  = 0;
207
208    if (int_part != 0.0) {
209        int_digits = (int)std::ceil(std::log10(int_part + 1.0));
210
211        int len = s.length();
212        s.append(int_digits);
213
214        bool zero_digits = (frac_part == 0.0 && fmt != SC_F);
215
216        for (i = int_digits + len - 1; i >= len; i--) {
217            unsigned int remainder = (unsigned int)std::fmod(int_part, 10.0);
218            s[i] = static_cast<char>('0' + remainder);
219
220            if (zero_digits) {
221                if (remainder == 0)
222                    int_zeros++;
223                else
224                    zero_digits = false;
225            }
226
227            int_part /= 10.0;
228        }
229
230        // discard trailing zeros from int_part
231        s.discard(int_zeros);
232
233        if (s[len] == '0') {
234            // int_digits was overestimated by one
235            s.remove(len);
236            --int_digits;
237        }
238    }
239
240    // print fractional part
241    int frac_digits = 0;
242    int frac_zeros  = 0;
243
244    if (frac_part != 0.0) {
245        s += '.';
246
247        bool zero_digits = (int_digits == 0 && fmt != SC_F);
248
249        frac_zeros = (int)std::floor(-std::log10(frac_part + DBL_EPSILON));
250
251        frac_part *= std::pow(10.0, frac_zeros);
252
253        frac_digits = frac_zeros;
254        if (!zero_digits) {
255            for (i = 0; i < frac_zeros; i++)
256                s += '0';
257            frac_zeros = 0;
258        }
259
260        while (frac_part != 0.0) {
261            frac_part *= 10.0;
262            int n = static_cast<int>(frac_part);
263
264            if (zero_digits) {
265                if (n == 0)
266                    frac_zeros++;
267                else
268                    zero_digits = false;
269            }
270
271            if (!zero_digits)
272                s += static_cast<char>('0' + n);
273
274            frac_part -= n;
275            frac_digits++;
276        }
277    }
278
279    // print exponent
280    if (fmt != SC_F) {
281        if (frac_digits == 0)
282            scfx_print_exp(s, int_zeros);
283        else if (int_digits == 0)
284            scfx_print_exp(s, -frac_zeros);
285    }
286}
287
288static void
289print_other(scfx_string &s, const scfx_ieee_double &id, sc_numrep numrep,
290             int w_prefix, sc_fmt fmt, const scfx_params *params)
291{
292    scfx_ieee_double id2 = id;
293
294    sc_numrep numrep2 = numrep;
295
296    bool numrep_is_sm = (numrep == SC_BIN_SM ||
297                         numrep == SC_OCT_SM ||
298                         numrep == SC_HEX_SM);
299
300    if (numrep_is_sm) {
301        if (id2.negative() != 0) {
302            s += '-';
303            id2.negative(0);
304        }
305        switch (numrep) {
306          case SC_BIN_SM:
307            numrep2 = SC_BIN_US;
308            break;
309          case SC_OCT_SM:
310            numrep2 = SC_OCT_US;
311            break;
312          case SC_HEX_SM:
313            numrep2 = SC_HEX_US;
314            break;
315          default:
316            ;
317        }
318    }
319
320    if (w_prefix != 0) {
321        scfx_print_prefix(s, numrep);
322    }
323
324    numrep = numrep2;
325
326    sc_fxval_fast a(id2);
327
328    int msb, lsb;
329
330    if (params != 0) {
331        msb = params->iwl() - 1;
332        lsb = params->iwl() - params->wl();
333
334        if (params->enc() == SC_TC_ &&
335            (numrep == SC_BIN_US ||
336              numrep == SC_OCT_US ||
337              numrep == SC_HEX_US) &&
338            !numrep_is_sm &&
339            params->wl() > 1) {
340            --msb;
341        } else if (params->enc() == SC_US_ &&
342            (numrep == SC_BIN ||
343              numrep == SC_OCT ||
344              numrep == SC_HEX ||
345              numrep == SC_CSD)) {
346            ++msb;
347        }
348    } else {
349        if (a.is_zero()) {
350            msb = 0;
351            lsb = 0;
352        } else {
353            msb = id2.exponent() + 1;
354            while (a.get_bit(msb) == a.get_bit(msb - 1))
355                --msb;
356
357            if (numrep == SC_BIN_US ||
358                numrep == SC_OCT_US ||
359                numrep == SC_HEX_US) {
360                --msb;
361            }
362
363            lsb = id2.exponent() - 52;
364            while (!a.get_bit(lsb))
365                ++lsb;
366        }
367    }
368
369    int step;
370
371    switch (numrep) {
372      case SC_BIN:
373      case SC_BIN_US:
374      case SC_CSD:
375        step = 1;
376       break;
377      case SC_OCT:
378      case SC_OCT_US:
379        step = 3;
380        break;
381      case SC_HEX:
382      case SC_HEX_US:
383        step = 4;
384        break;
385      default:
386        SC_REPORT_FATAL("assertion failed", "unexpected sc_numrep");
387        sc_core::sc_abort();
388    }
389
390    msb = (int)std::ceil(double(msb + 1) / step) * step - 1;
391
392    lsb = (int)std::floor(double(lsb) / step) * step;
393
394    if (msb < 0) {
395        s += '.';
396        if (fmt == SC_F) {
397            int sign = (id2.negative() != 0) ? (1 << step) - 1 : 0;
398            for (int i = (msb + 1) / step; i < 0; i++) {
399                if (sign < 10)
400                    s += static_cast<char>(sign + '0');
401                else
402                    s += static_cast<char>(sign + 'a' - 10);
403            }
404        }
405    }
406
407    int i = msb;
408    while (i >= lsb) {
409        int value = 0;
410        for (int j = step - 1; j >= 0; --j) {
411            value += static_cast<int>(a.get_bit(i)) << j;
412            --i;
413        }
414        if (value < 10)
415            s += static_cast<char>(value + '0');
416        else
417            s += static_cast<char>(value + 'a' - 10);
418        if (i == -1)
419            s += '.';
420    }
421
422    if (lsb > 0 && fmt == SC_F) {
423        for (int i = lsb / step; i > 0; i--)
424            s += '0';
425    }
426
427    if (s[s.length() - 1] == '.')
428        s.discard(1);
429
430    if (fmt != SC_F) {
431        if (msb < 0)
432            scfx_print_exp(s, (msb + 1) / step);
433        else if (lsb > 0)
434            scfx_print_exp(s, lsb / step);
435    }
436
437    if (numrep == SC_CSD)
438        scfx_tc2csd(s, w_prefix);
439}
440
441const char *
442to_string(const scfx_ieee_double &id, sc_numrep numrep, int w_prefix,
443          sc_fmt fmt, const scfx_params *params=0)
444{
445    static scfx_string s;
446
447    s.clear();
448
449    if (id.is_nan()) {
450        scfx_print_nan(s);
451    } else if (id.is_inf()) {
452        scfx_print_inf(s, static_cast<bool>(id.negative()));
453    } else if (id.negative() && !id.is_zero() &&
454             (numrep == SC_BIN_US ||
455               numrep == SC_OCT_US ||
456               numrep == SC_HEX_US)) {
457        s += "negative";
458    } else if (numrep == SC_DEC) {
459        sc_dt::print_dec(s, id, w_prefix, fmt);
460    } else {
461        sc_dt::print_other(s, id, numrep, w_prefix, fmt, params);
462    }
463
464    return s;
465}
466
467
468// explicit conversion to character string
469const std::string
470sc_fxval_fast::to_string() const
471{
472    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E));
473}
474
475const std::string
476sc_fxval_fast::to_string(sc_numrep numrep) const
477{
478    return std::string(sc_dt::to_string(m_val, numrep, -1, SC_E));
479}
480
481const std::string
482sc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix) const
483{
484    return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0),
485                       SC_E));
486}
487
488const std::string
489sc_fxval_fast::to_string(sc_fmt fmt) const
490{
491    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, fmt));
492}
493
494const std::string
495sc_fxval_fast::to_string(sc_numrep numrep, sc_fmt fmt) const
496{
497    return std::string(sc_dt::to_string(m_val, numrep, -1, fmt));
498}
499
500const std::string
501sc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const
502{
503    return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0),
504                                        fmt));
505}
506
507const std::string
508sc_fxval_fast::to_dec() const
509{
510    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E));
511}
512
513const std::string
514sc_fxval_fast::to_bin() const
515{
516    return std::string(sc_dt::to_string(m_val, SC_BIN, -1, SC_E));
517}
518
519const std::string
520sc_fxval_fast::to_oct() const
521{
522    return std::string(sc_dt::to_string(m_val, SC_OCT, -1, SC_E));
523}
524
525const std::string
526sc_fxval_fast::to_hex() const
527{
528    return std::string(sc_dt::to_string(m_val, SC_HEX, -1, SC_E));
529}
530
531
532// print or dump content
533
534void
535sc_fxval_fast::print(::std::ostream &os) const
536{
537    os << sc_dt::to_string(m_val, SC_DEC, -1, SC_E);
538}
539
540void
541sc_fxval_fast::scan(::std::istream &is)
542{
543    std::string s;
544    is >> s;
545    *this = s.c_str();
546}
547
548void
549sc_fxval_fast::dump(::std::ostream &os) const
550{
551    os << "sc_fxval_fast" << ::std::endl;
552    os << "(" << ::std::endl;
553    os << "val = " << m_val << ::std::endl;
554    // TO BE COMPLETED
555    // os << "r_flag   = " << m_r_flag << ::std::endl;
556    // os << "observer = ";
557    // if (m_observer != 0)
558    //     m_observer->dump(os);
559    // else
560    //     os << "0" << ::std::endl;
561    os << ")" << ::std::endl;
562}
563
564
565// internal use only;
566bool
567sc_fxval_fast::get_bit(int i) const
568{
569    scfx_ieee_double id(m_val);
570    if (id.is_zero() || id.is_nan() || id.is_inf())
571        return false;
572
573    // convert to two's complement
574    unsigned int m0 = id.mantissa0();
575    unsigned int m1 = id.mantissa1();
576
577    if (id.is_normal())
578        m0 += 1U << 20;
579
580    if (id.negative() != 0) {
581        m0 = ~ m0;
582        m1 = ~ m1;
583        unsigned int tmp = m1;
584        m1 += 1U;
585        if (m1 <= tmp)
586            m0 += 1U;
587    }
588
589    // get the right bit
590    int j = i - id.exponent();
591    if ((j += 20) >= 32)
592        return ((m0 & 1U << 31) != 0);
593    else if (j >= 0)
594        return ((m0 & 1U << j) != 0);
595    else if ((j += 32) >= 0)
596        return ((m1 & 1U << j) != 0);
597    else
598        return false;
599}
600
601
602// protected methods and friend functions
603sc_fxval_fast_observer *
604sc_fxval_fast::lock_observer() const
605{
606    SC_ASSERT_(m_observer != 0, "lock observer failed");
607    sc_fxval_fast_observer *tmp = m_observer;
608    m_observer = 0;
609    return tmp;
610}
611
612void
613sc_fxval_fast::unlock_observer(sc_fxval_fast_observer *observer_) const
614{
615    SC_ASSERT_(observer_ != 0, "unlock observer failed");
616    m_observer = observer_;
617}
618
619#define SCFX_FAIL_IF_(cnd)                                                    \
620{                                                                             \
621    if ((cnd))                                                             \
622        return static_cast<double>(scfx_ieee_double::nan());                \
623}
624
625double
626sc_fxval_fast::from_string(const char *s)
627{
628    SCFX_FAIL_IF_(s == 0 || *s == 0);
629
630    scfx_string s2;
631    s2 += s;
632    s2 += '\0';
633
634    bool sign_char;
635    int sign = scfx_parse_sign(s, sign_char);
636
637    sc_numrep numrep = scfx_parse_prefix(s);
638
639    int base = 0;
640
641    switch (numrep) {
642      case SC_DEC:
643        {
644            base = 10;
645            if (scfx_is_nan(s)) // special case: NaN
646                return static_cast<double>(scfx_ieee_double::nan());
647            if (scfx_is_inf(s)) // special case: Infinity
648                return static_cast<double>(scfx_ieee_double::inf(sign));
649            break;
650        }
651      case SC_BIN:
652      case SC_BIN_US:
653        {
654            SCFX_FAIL_IF_(sign_char);
655            base = 2;
656            break;
657        }
658
659      case SC_BIN_SM:
660        {
661            base = 2;
662            break;
663        }
664      case SC_OCT:
665      case SC_OCT_US:
666        {
667            SCFX_FAIL_IF_(sign_char);
668            base = 8;
669            break;
670        }
671      case SC_OCT_SM:
672        {
673            base = 8;
674            break;
675        }
676      case SC_HEX:
677      case SC_HEX_US:
678        {
679            SCFX_FAIL_IF_(sign_char);
680            base = 16;
681            break;
682        }
683      case SC_HEX_SM:
684        {
685            base = 16;
686            break;
687        }
688      case SC_CSD:
689        {
690            SCFX_FAIL_IF_(sign_char);
691            base = 2;
692            scfx_csd2tc(s2);
693            s = (const char*) s2 + 4;
694            numrep = SC_BIN;
695            break;
696        }
697      default:;// Martin, what is default???
698    }
699
700    //
701    // find end of mantissa and count the digits and points
702    //
703
704    const char *end = s;
705    bool based_point = false;
706    int int_digits = 0;
707    int frac_digits = 0;
708
709    while (*end) {
710        if (scfx_exp_start(end))
711            break;
712
713        if (*end == '.') {
714            SCFX_FAIL_IF_(based_point);
715            based_point = true;
716        } else {
717            SCFX_FAIL_IF_(!scfx_is_digit(*end, numrep));
718            if (based_point)
719                frac_digits++;
720            else
721                int_digits++;
722        }
723
724        end++;
725    }
726
727    SCFX_FAIL_IF_(int_digits == 0 && frac_digits == 0);
728
729    // [ exponent ]
730    int exponent = 0;
731    if (*end) {
732        for (const char *e = end + 2; *e; e++)
733            SCFX_FAIL_IF_(!scfx_is_digit(*e, SC_DEC));
734        exponent = std::atoi(end + 1);
735    }
736
737    //
738    // convert the mantissa
739    //
740    double integer = 0.0;
741    if (int_digits != 0) {
742        bool first_digit = true;
743
744        for (; s < end; s++) {
745            if (*s == '.')
746                break;
747
748            if (first_digit) {
749                integer = scfx_to_digit(*s, numrep);
750                switch (numrep) {
751                  case SC_BIN:
752                  case SC_OCT:
753                  case SC_HEX:
754                    {
755                        if (integer >= (base >> 1))
756                            integer -= base; // two's complement
757                        break;
758                    }
759                  default:
760                    ;
761                }
762                first_digit = false;
763            } else {
764                integer *= base;
765                integer += scfx_to_digit(*s, numrep);
766            }
767        }
768    }
769
770    // [ . fraction ]
771    double fraction = 0.0;
772    if (frac_digits != 0) {
773        s++;  // skip '.'
774
775        bool first_digit = (int_digits == 0);
776        double scale = 1.0;
777        for (; s < end; s++) {
778            scale /= base;
779
780            if (first_digit) {
781                fraction = scfx_to_digit(*s, numrep);
782                switch (numrep) {
783                  case SC_BIN:
784                  case SC_OCT:
785                  case SC_HEX:
786                    {
787                        if (fraction >= (base >> 1))
788                            fraction -= base; // two's complement
789                        break;
790                    }
791                  default:
792                    ;
793                }
794                fraction *= scale;
795                first_digit = false;
796            } else {
797                fraction += scfx_to_digit(*s, numrep) * scale;
798            }
799        }
800    }
801
802    double exp =
803        (exponent != 0) ? std::pow((double) base, (double) exponent) : 1;
804
805    return (sign * (integer + fraction) * exp);
806}
807
808#undef SCFX_FAIL_IF_
809
810} // namespace sc_dt
811