view libinterp/corefcn/hex2num.cc @ 20812:d9ca869ca124

maint: Clean-up more instances of print_usage(). * mk-opts.pl: Fix script that generates *-opt.cc files to put print_usage() first. * __ilu__.cc (F__ilutp__): Don't declare and initialize multiple comma separated variables. * __lin_interpn__.cc (F__lin_interpn__): Eliminate extra spaces in if conditional. * dasrt.cc (Fdasrt): Declare variables only as needed, in this case, after input validation has succeeded. * file-io.cc (Frewind): Declare variables after input validation succeeds. * file-io.cc (Ftempname): Rename variable len to nargin to match rest of code. * gammainc.cc (Fgammainc): Put nargin checking first in function. * hex2num.cc (Fhex2num, Fnum2hex): Declare "octave_value retval;" first in function to match rest of Octave code base. * load-path.cc (Frmpath): Re-phrase comment. * lu.cc (Flu): Declare variables after input validation succeeds. Use space after ! operator. * lu.cc (Fluupdate): Place octave_value_list declaration first in function. Declare variables after input validation succeeds. * matrix_type.cc (Fmatrix_type): Place octave_value declaration first in function. * tril.cc (do_trilu): Move nargin checking higher in function. * utils.cc (Fdir_in_loadpath): Declare variables after input validation succeeds. * __glpk__.cc (F__glpk__): Rename variable nrhs to nargin to match rest of code base. * __magick_read__.cc (F__magick_ping__, F__magick_formats__): Add newline to space out code for readability. * __osmesa_print__.cc (F__osmesa_print__): Use DeMorgan's Law to simplify nargin validation. * audiodevinfo.cc (F__recorder_record__): Correct indentation. * chol.cc (Fcholinsert, Fcholdelete, Fcholshift): Place octave_value_list declaration first in function. * dmperm.cc (Fdmperm, Fsprank): Place octave_value_list declaration first in function. * qr.cc (Fqrupdate, Fqrinsert, Fqrdelete, Fqrshift): Place octave_value_list declaration first in function. * lex.ll (Fiskeyword): Rewrite function to use modern syntax. Add BIST tests for special words "get", "set". Add BIST tests for input validation.
author Rik <rik@octave.org>
date Sat, 05 Dec 2015 15:59:22 -0800
parents 8bb38ba1bad6
children f428cbe7576f
line wrap: on
line source

/*

Copyright (C) 2008-2015 David Bateman

This file is part of Octave.

Octave is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

Octave is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Octave; see the file COPYING.  If not, see
<http://www.gnu.org/licenses/>.

*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <algorithm>

#include "defun.h"
#include "error.h"
#include "gripes.h"
#include "oct-obj.h"
#include "utils.h"

DEFUN (hex2num, args, ,
       "-*- texinfo -*-\n\
@deftypefn  {Built-in Function} {@var{n} =} hex2num (@var{s})\n\
@deftypefnx {Built-in Function} {@var{n} =} hex2num (@var{s}, @var{class})\n\
Typecast the 16 character hexadecimal character string to an IEEE 754\n\
double precision number.\n\
\n\
If fewer than 16 characters are given the strings are right padded with\n\
@qcode{'0'} characters.\n\
\n\
Given a string matrix, @code{hex2num} treats each row as a separate number.\n\
\n\
@example\n\
@group\n\
hex2num ([\"4005bf0a8b145769\"; \"4024000000000000\"])\n\
   @result{} [2.7183; 10.000]\n\
@end group\n\
@end example\n\
\n\
The optional argument @var{class} can be passed as the string\n\
@qcode{\"single\"} to specify that the given string should be interpreted as\n\
a single precision number.  In this case, @var{s} should be an 8 character\n\
hexadecimal string.  For example:\n\
\n\
@example\n\
@group\n\
hex2num ([\"402df854\"; \"41200000\"], \"single\")\n\
   @result{} [2.7183; 10.000]\n\
@end group\n\
@end example\n\
@seealso{num2hex, hex2dec, dec2hex}\n\
@end deftypefn")
{
  octave_value retval;
  int nargin = args.length ();

  if (nargin < 1 || nargin > 2)
    print_usage ();

  if (nargin == 2 && ! args(1).is_string ())
    error ("hex2num: CLASS must be a string");
  else
    {
      const charMatrix cmat = args(0).char_matrix_value ();
      std::string prec = (nargin == 2) ? args(1).string_value () : "double";
      bool is_single = (prec == "single");
      octave_idx_type nchars = (is_single) ? 8 : 16;

      if (cmat.columns () > nchars)
        error ("hex2num: S must be no more than %d characters", nchars);
      else if (prec != "double" && prec != "single")
        error ("hex2num: CLASS must be either \"double\" or \"single\"");
      else
        {
          octave_idx_type nr = cmat.rows ();
          octave_idx_type nc = cmat.columns ();

          if (is_single)
            {
              FloatColumnVector m (nr);

              for (octave_idx_type i = 0; i < nr; i++)
                {
                  union
                  {
                    uint32_t ival;
                    float dval;
                  } num;

                  num.ival = 0;

                  for (octave_idx_type j = 0; j < nc; j++)
                    {
                      unsigned char ch = cmat.elem (i, j);

                      if (isxdigit (ch))
                        {
                          num.ival <<= 4;
                          if (ch >= 'a')
                            num.ival += static_cast<uint32_t> (ch - 'a' + 10);
                          else if (ch >= 'A')
                            num.ival += static_cast<uint32_t> (ch - 'A' + 10);
                          else
                            num.ival += static_cast<uint32_t> (ch - '0');
                        }
                      else
                        {
                          error ("hex2num: illegal character found in string S");
                          break;
                        }
                    }

                  if (nc < nchars)
                    num.ival <<= (nchars - nc) * 4;

                  m(i) = num.dval;
                }

              retval =  m;
            }
          else
            {
              ColumnVector m (nr);

              for (octave_idx_type i = 0; i < nr; i++)
                {
                  union
                  {
                    uint64_t ival;
                    double dval;
                  } num;

                  num.ival = 0;

                  for (octave_idx_type j = 0; j < nc; j++)
                    {
                      unsigned char ch = cmat.elem (i, j);

                      if (isxdigit (ch))
                        {
                          num.ival <<= 4;
                          if (ch >= 'a')
                            num.ival += static_cast<uint64_t> (ch - 'a' + 10);
                          else if (ch >= 'A')
                            num.ival += static_cast<uint64_t> (ch - 'A' + 10);
                          else
                            num.ival += static_cast<uint64_t> (ch - '0');
                        }
                      else
                        {
                          error ("hex2num: illegal character found in string S");
                          break;
                        }
                    }

                  if (nc < nchars)
                    num.ival <<= (nchars - nc) * 4;

                  m(i) = num.dval;
                }

              retval =  m;
            }
        }
    }

  return retval;
}

/*
%!assert (hex2num (["c00";"bff";"000";"3ff";"400"]), [-2:2]')
%!assert (hex2num (["c00";"bf8";"000";"3f8";"400"], "single"), single([-2:2])')
*/

DEFUN (num2hex, args, ,
       "-*- texinfo -*-\n\
@deftypefn {Built-in Function} {@var{s} =} num2hex (@var{n})\n\
Typecast a double or single precision number or vector to a 8 or 16\n\
character hexadecimal string of the IEEE 754 representation of the number.\n\
\n\
For example:\n\
\n\
@example\n\
@group\n\
num2hex ([-1, 1, e, Inf])\n\
@result{} \"bff0000000000000\n\
    3ff0000000000000\n\
    4005bf0a8b145769\n\
    7ff0000000000000\"\n\
@end group\n\
@end example\n\
\n\
If the argument @var{n} is a single precision number or vector, the returned\n\
string has a length of 8.  For example:\n\
\n\
@example\n\
@group\n\
num2hex (single ([-1, 1, e, Inf]))\n\
@result{} \"bf800000\n\
    3f800000\n\
    402df854\n\
    7f800000\"\n\
@end group\n\
@end example\n\
@seealso{hex2num, hex2dec, dec2hex}\n\
@end deftypefn")
{
  octave_value retval;
  int nargin = args.length ();

  if (nargin != 1)
    print_usage ();

  if (args(0).is_single_type ())
    {
      const FloatColumnVector v (args(0).float_vector_value ());

      octave_idx_type nchars = 8;
      octave_idx_type nr = v.numel ();
      charMatrix m (nr, nchars);
      const float *pv = v.fortran_vec ();

      for (octave_idx_type i = 0; i < nr; i++)
        {
          union
          {
            uint32_t ival;
            float dval;
          } num;

          num.dval = *pv++;

          for (octave_idx_type j = 0; j < nchars; j++)
            {
              unsigned char ch =
                static_cast<char>(num.ival >> ((nchars - 1 - j) * 4) & 0xF);
              if (ch >= 10)
                ch += 'a' - 10;
              else
                ch += '0';

              m.elem (i, j) = ch;
            }
        }

      retval = m;
    }
  else
    {
      const ColumnVector v (args(0).vector_value ());

      octave_idx_type nchars = 16;
      octave_idx_type nr = v.numel ();
      charMatrix m (nr, nchars);
      const double *pv = v.fortran_vec ();

      for (octave_idx_type i = 0; i < nr; i++)
        {
          union
          {
            uint64_t ival;
            double dval;
          } num;

          num.dval = *pv++;

          for (octave_idx_type j = 0; j < nchars; j++)
            {
              unsigned char ch =
                static_cast<char>(num.ival >> ((nchars - 1 - j) * 4) & 0xF);
              if (ch >= 10)
                ch += 'a' - 10;
              else
                ch += '0';

              m.elem (i, j) = ch;
            }
        }

      retval = m;
    }

  return retval;
}

/*
%!assert (num2hex (-2:2), ["c000000000000000";"bff0000000000000";"0000000000000000";"3ff0000000000000";"4000000000000000"])
%!assert (num2hex (single (-2:2)), ["c0000000";"bf800000";"00000000";"3f800000";"40000000"])
*/