diff --git a/components/number.inc b/components/number.inc
index 907d524..6b79ff2 100644
--- a/components/number.inc
+++ b/components/number.inc
@@ -277,9 +277,17 @@ function _webform_render_number($component, $value = NULL, $filter = TRUE) {
     '#max' => $component['extra']['max'],
     '#step' => $component['extra']['step'] ? abs($component['extra']['step']) : '',
     '#integer' => $component['extra']['integer'],
+    '#point' => $component['extra']['point'],
+    '#separator' => $component['extra']['separator'],
+    '#decimals' => $component['extra']['decimals'],
     '#translatable' => array('title', 'description'),
   );
 
+  // Set the decimal count to zero for integers.
+  if ($element['#integer'] && $element['#decimals'] === '') {
+    $element['#decimals'] = 0;
+  }
+
   // Flip the min and max properties to make min less than max if needed.
   if ($element['#min'] !== '' && $element['#max'] !== '' && $element['#min'] > $element['#max']) {
     $max = $element['#min'];
@@ -319,7 +327,15 @@ function _webform_render_number($component, $value = NULL, $filter = TRUE) {
 
   // Set user-entered values.
   if (isset($value[0])) {
-    $element['#default_value'] = $value[0];
+    // If the value has been standardized, convert it to the expected format
+    // for display to the user.
+    if (webform_number_format_match($value[0], '.', '')) {
+      $element['#default_value'] = _webform_number_format($component, $value[0]);
+    }
+    // Otherwise use the user-defined input.
+    else {
+      $element['#default_value'] = $value[0];
+    }
   }
 
   // Enforce uniqueness.
@@ -569,12 +585,20 @@ function _webform_csv_data_number($component, $export_options, $value) {
  *   None. Calls a form_set_error if the number is not valid.
  */
 function _webform_validate_number($element, &$form_state) {
+  // Trim spaces for basic cleanup.
   $value = trim($element['#value']);
   form_set_value($element, $value, $form_state);
 
   if ($value != '') {
+    // First check that the entered value matches the expected value.
+    if (!webform_number_format_match($value, $element['#point'], $element['#separator'])) {
+      form_error($element, t('%name field value must format numbers as "@example".', array('%name' => $element['#title'], '@example' => webform_number_format(12345.6789, $element['#decimals'], $element['#point'], $element['#separator']))));
+      return;
+    }
+
     // Numeric test.
-    if (is_numeric($value)) {
+    $numeric_value = webform_number_standardize($value, $element['#point']);
+    if (is_numeric($numeric_value)) {
       // Range test.
       if ($element['#min'] != '' && $element['#max'] != '') {
         // Flip minimum and maximum if needed.
@@ -586,25 +610,25 @@ function _webform_validate_number($element, &$form_state) {
           $min = $element['#max'];
           $max = $element['#min'];
         }
-        if ($value > $max || $value < $min) {
-          form_error($element, t('%name field value of @value should be in the range @min to @max.', array('%name' => $element['#title'], '@value' => $value, '@min' => $min, '@max' => $max)));
+        if ($numeric_value > $max || $numeric_value < $min) {
+          form_error($element, t('%name field value of @value should be in the range @min to @max.', array('%name' => $element['#title'], '@value' => $value, '@min' => $element['#min'], '@max' => $element['#max'])));
         }
       }
-      elseif ($element['#max'] != '' && $value > $element['#max']) {
+      elseif ($element['#max'] != '' && $numeric_value > $element['#max']) {
         form_error($element, t('%name field value must be less than @max.', array('%name' => $element['#title'], '@max' => $element['#max'])));
       }
-      elseif ($element['#min'] != '' && $value < $element['#min']) {
+      elseif ($element['#min'] != '' && $numeric_value < $element['#min']) {
         form_error($element, t('%name field value must be greater than @min.', array('%name' => $element['#title'], '@min' => $element['#min'])));
       }
 
       // Integer test.
-      if ($element['#integer'] && !is_int($value * 1)) {
+      if ($element['#integer'] && !is_int($numeric_value * 1)) {
         form_error($element, t('%name field value of @value must be an integer.', array('%name' => $element['#title'], '@value' => $value)));
       }
 
       // Step test.
       $starting_number = $element['#min'] ? $element['#min'] : 0;
-      if ($element['#step'] != 0 && webform_modulo($element['#value'] - $starting_number, $element['#step']) != 0) {
+      if ($element['#step'] != 0 && webform_modulo($numeric_value - $starting_number, $element['#step']) != 0) {
         $samples = array(
           $starting_number,
           $starting_number + ($element['#step'] * 1),
@@ -623,7 +647,20 @@ function _webform_validate_number($element, &$form_state) {
       form_error($element, t('%name field value of @value must be numeric.', array('%name' => $element['#title'], '@value' => $value)));
     }
   }
+}
 
+/**
+ * Implements _webform_submit_component().
+ */
+function _webform_submit_number($component, $value) {
+  // Because _webform_validate_number() ensures the format matches when moving
+  // forward through a form, this should always pass before saving into the
+  // database. When moving backwards in a form, do not adjust the value, since
+  // it has not yet been validated.
+  if (webform_number_format_match($value, $component['extra']['point'], $component['extra']['separator'])) {
+    $value = webform_number_standardize($value, $component['extra']['point']);
+  }
+  return $value;
 }
 
 /**
@@ -729,15 +766,38 @@ function _webform_number_select_options($component) {
 }
 
 /**
- * Apply number format.
+ * Apply number format based on a component and number value.
  */
 function _webform_number_format($component, $value) {
+  return webform_number_format($value, $component['extra']['decimals'], $component['extra']['point'], $component['extra']['separator']);
+}
+
+/**
+ * Validates if a provided number string matches an expected format.
+ *
+ * This function allows the thousands separator to be optional, but decimal
+ * points must be in the right location.
+ *
+ * Based on http://stackoverflow.com/questions/5917082/regular-expression-to-match-numbers-with-or-without-commas-and-decimals-in-text.
+ */
+function webform_number_format_match($value, $point, $separator) {
+  return preg_match('/^([1-9](?:\d{0,2})(?:' . ($separator ? (preg_quote($separator, '/') . '?') : '') . '\d{3})*(?:' . preg_quote($point, '/') . '\d*[0-9])?|0?' . preg_quote($point, '/') . '\d*[1-9]|0)$/', $value);
+}
+
+/**
+ * Format a number with thousands separator, decimal point, and decimal places.
+ *
+ * This function is a wrapper around PHP's native number_format(), but allows
+ * the decimal places parameter to be NULL or an empty string, resulting in a
+ * behavior of no change to the decimal places.
+ */
+function webform_number_format($value, $decimals = NULL, $point = '.', $separator = ',') {
   if (!is_numeric($value)) {
     return '';
   }
+
   // If no decimal places are specified, do a best guess length of decimals.
-  $decimals = $component['extra']['decimals'];
-  if ($decimals === '') {
+  if (is_null($decimals) || $decimals === '') {
     // If it's an integer, no decimals needed.
     if (is_int(($value . '') * 1)) {
       $decimals = 0;
@@ -750,7 +810,23 @@ function _webform_number_format($component, $value) {
     }
   }
 
-  return number_format($value, $decimals, $component['extra']['point'], $component['extra']['separator']);
+  return number_format($value, $decimals, $point, $separator);
+}
+
+/**
+ * Given a number, convert it to string compatible with a PHP float.
+ *
+ * @param string $value
+ *   The string value to be standardized into a numeric string.
+ * @param $point
+ *   The point separator between the whole number and the decimals.
+ */
+function webform_number_standardize($value, $point) {
+  // For simplicity, strip everything that's not the decimal point.
+  $value = preg_replace('/[^0-9' . preg_quote($point, '/') . ']/', '', $value);
+  // Convert the decimal point to a period.
+  $value = str_replace($point, '.', $value);
+  return $value;
 }
 
 /**
