diff --git a/libinterp/corefcn/ls-mat-ascii.cc b/libinterp/corefcn/ls-mat-ascii.cc
--- a/libinterp/corefcn/ls-mat-ascii.cc
+++ b/libinterp/corefcn/ls-mat-ascii.cc
@@ -60,43 +60,62 @@ along with Octave; see the file COPYING.
 #include "variables.h"
 #include "version.h"
 
+static std::istream&
+getline_alleol (std::istream& is, std::string& str)
+{
+  char c;
+
+  str.clear ();
+  while (1)
+    {
+      is.read (&c, 1);
+      if (is.fail ())
+        break;
+      if (c == 0x0A)
+        break;
+      else if (c == 0x0D)
+        {
+          is.read (&c, 1);
+          if (is.fail ())
+            {
+              is.clear ();
+              break;
+            }
+          if (c != 0x0A)
+            is.seekg (-1, std::ios_base::cur);
+          break;
+        } else
+          str.push_back(c);
+    }
+
+    return is;
+}
+
+// Return a line of data. Comments and empty/white line(s) will be skipped.
+
 static std::string
 get_mat_data_input_line (std::istream& is)
 {
   std::string retval;
-
-  bool have_data = false;
+  bool no_data_found;
 
   do
     {
-      retval = "";
+      getline_alleol (is, retval);
 
-      char c;
-      while (is.get (c))
-        {
-          if (c == '\n' || c == '\r')
-            {
-              is.putback (c);
-              skip_preceeding_newline (is);
-              break;
-            }
+      // Remove tailing '\r'.
+      while (retval.size () && retval.back () == '\r')
+        retval.pop_back ();
 
-          if (c == '%' || c == '#')
-            {
-              skip_until_newline (is, false);
-              break;
-            }
+      // Remove any comment.
+      size_t pos_comment = retval.find_first_of ("#%");
+      if (pos_comment != std::string::npos)
+        retval.erase (pos_comment);
 
-          if (! is.eof ())
-            {
-              if (! have_data && c != ' ' && c != '\t')
-                have_data = true;
-
-              retval += c;
-            }
-        }
+      // Detect non-whitespace.
+      no_data_found = (retval.find_first_not_of (" \t") == std::string::npos);
     }
-  while (! (have_data || is.eof ()));
+  while (no_data_found && ! is.eof ());
 
   return retval;
 }
@@ -211,6 +230,51 @@ done:
   is.seekg (pos);
 }
 
+// Mostly copy from lo-utils.cc
+template <typename T>
+T str2fp_num (const char *nptr, char **endptr);
+
+template <> double str2fp_num<double> (const char *nptr, char **endptr)
+{
+  return strtod (nptr, endptr);
+}
+
+template <typename T>
+T
+str2fp_num (const std::string &str, std::string::size_type pos,
+            std::string::size_type &end_pos)
+{
+  if (pos >= str.size ())
+    {
+      // Follow convention of strtod().
+      end_pos = pos;
+      return T (0.0);
+    }
+
+  char *end_ptr;
+  const char *beg_ptr = str.c_str () + pos;
+
+  T val = str2fp_num<T> (beg_ptr, &end_ptr);
+
+  if (beg_ptr == end_ptr)
+    {
+      // Error during conversion.
+      if (str.size () - pos >= 2
+          && std::toupper (str[pos])   == 'N'
+          && std::toupper (str[pos+1]) == 'A')
+        {
+          // Found NA
+          val = octave::numeric_limits<T>::NA ();
+          end_ptr += 2;
+        }
+    }
+
+  end_pos = pos + static_cast<std::string::size_type> (end_ptr - beg_ptr);
+
+  return val;
+}
+
+
 // Extract a matrix from a file of numbers only.
 //
 // Comments are not allowed.  The file should only have numeric values.
@@ -269,6 +333,7 @@ read_mat_ascii_data (std::istream& is, c
            filename.c_str ());
 
   Matrix tmp (nr, nc);
+  std::string buf;
 
   if (nr < 1 || nc < 1)
     is.clear (std::ios::badbit);
@@ -277,59 +342,49 @@ read_mat_ascii_data (std::istream& is, c
       double d;
       for (octave_idx_type i = 0; i < nr; i++)
         {
-          std::string buf = get_mat_data_input_line (is);
+          bool no_data_found;
+          do
+            {
+              getline_alleol (is, buf);
 
-          std::istringstream tmp_stream (buf);
+              // Detect non-whitespace.
+              no_data_found = (buf.find_first_not_of (" \t") ==
+                               std::string::npos);
+            }
+          while (no_data_found && ! is.eof ());
+
+          std::string::size_type consumed_pos = 0;
+          std::string::size_type parsed_pos;
 
           for (octave_idx_type j = 0; j < nc; j++)
             {
-              octave_quit ();
+              d = str2fp_num<double> (buf, consumed_pos, parsed_pos);
+              if (consumed_pos == parsed_pos)
+                break;  // No numerics left or error conversion.
 
-              d = octave_read_value<double> (tmp_stream);
-
-              if (! tmp_stream && ! tmp_stream.eof ())
-                error ("load: failed to read matrix from file '%s'",
-                       filename.c_str ());
-
-              tmp.elem (i, j) = d;
+              tmp.xelem (i, j) = d;
               total_count++;
 
-              // Skip whitespace and commas.
-              char c;
-              while (1)
-                {
-                  tmp_stream >> c;
+              if (parsed_pos >= buf.size ())
+                break;
 
-                  if (! tmp_stream)
-                    break;
-
-                  if (! (c == ' ' || c == '\t' || c == ','))
-                    {
-                      tmp_stream.putback (c);
-                      break;
-                    }
-                }
-
-              if (tmp_stream.eof ())
-                break;
+              // Skip delimiters
+              consumed_pos = buf.find_first_not_of (" \t,", parsed_pos);
             }
         }
     }
 
   if (! is && ! is.eof ())
-    error ("load: failed to read matrix from file '%s'",
-           filename.c_str ());
+    error ("load: failed to read matrix from file '%s'", filename.c_str ());
 
   // FIXME: not sure this is best, but it works.
-
   if (is.eof ())
     is.clear ();
 
   octave_idx_type expected = nr * nc;
 
   if (expected != total_count)
-    error ("load: expected %d elements, found %d",
-           expected, total_count);
+    error ("load: expected %d elements, found %d", expected, total_count);
 
   tc = tmp;
 
diff --git a/liboctave/util/lo-utils.cc b/liboctave/util/lo-utils.cc
--- a/liboctave/util/lo-utils.cc
+++ b/liboctave/util/lo-utils.cc
@@ -198,122 +198,87 @@ octave_fgetl (FILE *f, bool& eof)
   return retval;
 }
 
-// Note that the caller is responsible for repositioning the stream on failure.
+// Convert char* to a floating-point number.
+template <typename T>
+T str2fp_num (const char *nptr, char **endptr);
+
+template <> float str2fp_num<float> (const char *nptr, char **endptr)
+{
+  return strtof (nptr, endptr);
+}
+
+template <> double str2fp_num<double> (const char *nptr, char **endptr)
+{
+  return strtod (nptr, endptr);
+}
+
+template <> long double str2fp_num<long double> (const char *nptr,
+                                                 char **endptr)
+{
+  return strtold (nptr, endptr);
+}
+
+// Read a float/double/long double value.  Discard any sign on NaN and NA.
+// On error, 0 will be returned, stream position reset, and failbit set.
 
 template <typename T>
 T
-read_inf_nan_na (std::istream& is, char c0)
-{
-  T val = 0.0;
-
-  switch (c0)
-    {
-    case 'i': case 'I':
-      {
-        char c1 = is.get ();
-        if (c1 == 'n' || c1 == 'N')
-          {
-            char c2 = is.get ();
-            if (c2 == 'f' || c2 == 'F')
-              val = std::numeric_limits<T>::infinity ();
-            else
-              is.setstate (std::ios::failbit);
-          }
-        else
-          is.setstate (std::ios::failbit);
-      }
-      break;
-
-    case 'n': case 'N':
-      {
-        char c1 = is.get ();
-        if (c1 == 'a' || c1 == 'A')
-          {
-            char c2 = is.get ();
-            if (c2 == 'n' || c2 == 'N')
-              val = std::numeric_limits<T>::quiet_NaN ();
-            else
-              {
-                val = octave::numeric_limits<T>::NA ();
-                if (c2 != std::istream::traits_type::eof ())
-                  is.putback (c2);
-              }
-          }
-        else
-          is.setstate (std::ios::failbit);
-      }
-      break;
-
-    default:
-      (*current_liboctave_error_handler) ("read_inf_nan_na: invalid character '%c'");
-    }
-
-  return val;
-}
-
-// Read a double value.  Discard any sign on NaN and NA.
-
-template <typename T>
-double
 octave_read_fp_value (std::istream& is)
 {
-  T val = 0.0;
-
   // FIXME: resetting stream position is likely to fail unless we are
   // reading from a file.
   std::ios::streampos pos = is.tellg ();
 
-  char c1 = ' ';
+  char *end_ptr;
+  std::string str_chunk;
 
-  while (isspace (c1))
-    c1 = is.get ();
+  is >> str_chunk;
 
-  bool neg = false;
+  const char *beg_ptr = str_chunk.c_str ();
 
-  switch (c1)
+  errno = 0;
+  T val = str2fp_num<T> (beg_ptr, &end_ptr);
+
+  if (beg_ptr == end_ptr)
     {
-    case '-':
-      neg = true;
-      OCTAVE_FALLTHROUGH;
-
-    case '+':
-      {
-        char c2 = 0;
-        c2 = is.get ();
-        if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
-          val = read_inf_nan_na<T> (is, c2);
-        else
-          {
-            is.putback (c2);
-            is >> val;
-          }
-
-        if (neg && ! is.fail ())
-          val = -val;
-      }
-      break;
-
-    case 'i': case 'I':
-    case 'n': case 'N':
-      val = read_inf_nan_na<T> (is, c1);
-      break;
-
-    default:
-      is.putback (c1);
-      is >> val;
-      break;
+      // Error during conversion.
+      if (str_chunk.size () >= 2
+          && std::toupper (str_chunk[0]) == 'N'
+          && std::toupper (str_chunk[1]) == 'A')
+        {
+          // Found NA
+          val = octave::numeric_limits<T>::NA ();
+          end_ptr += 2;
+        }
+      else
+        is.setstate (std::ios_base::failbit);
+    }
+  else
+    {
+      if (std::isinf (val) && errno == ERANGE)
+        {
+          // Report out of range as failbit.
+          is.setstate (std::ios_base::failbit);
+        }
+      // FIXME: Should we rely on undocumented implementation?
+      // Note: For NaN input, current implementation (GNU glibc 2.24) of
+      // strtod() will drop the sign and the payload of NaN, so no extra
+      // work needs to be done here.  Although, this disagrees with the
+      // man page (strtod(3)).
     }
 
   std::ios::iostate status = is.rdstate ();
   if (status & std::ios::failbit)
     {
-      // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
-      if (val == std::numeric_limits<T>::max ())
+      // Convert +/- HUGE_VALF returned by C++ strtof for very large numbers to Inf
+      if (val == HUGE_VALF)
         {
-          if (neg)
-            val = -std::numeric_limits<T>::infinity ();
-          else
-            val = std::numeric_limits<T>::infinity ();
+          val = std::numeric_limits<T>::infinity ();
+          is.clear (status & ~std::ios::failbit);
+        }
+      else if (val == -HUGE_VALF)
+        {
+          val = -std::numeric_limits<T>::infinity ();
           is.clear (status & ~std::ios::failbit);
         }
       else
@@ -324,6 +289,17 @@ octave_read_fp_value (std::istream& is)
           is.setstate (status);
         }
     }
+  else if (static_cast<size_t> (end_ptr - beg_ptr) != str_chunk.size ())
+    {
+      // Advance only what we have consumed for parsing.
+      is.seekg (pos + (end_ptr - beg_ptr));
+
+      // FIXME: Can we delete this?  Input is is of type std::istream
+      // Clear eof.
+      // Note in C++11, std::istream::seekg clears eofbit.
+      // But seems that seekg() do not work with octave_istrstream correctly.
+      //is.clear (status & ~std::ios::eofbit);
+    }
 
   return val;
 }
