diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,7 +1,34 @@
 * Hackage: <http://hackage.haskell.org/package/crackNum>
 * GitHub:  <http://github.com/LeventErkok/crackNum/>
 
-* Latest Hackage released version: 4.5, 2026-09-01
+* Latest Hackage released version: 4.6, 2026-09-03
+
+### Version 4.6, 2026-09-03
+
+  * New floating-point format: UE5M3, selected with `-fue5m3`. This is the unsigned
+    FP8 scale format proposed for FP4 microscaling. It is `E4M3` with the sign bit --
+    which a scale, being non-negative, never uses -- repurposed as the exponent's top
+    bit, giving 5 exponent bits and 3 significand bits in the same 8. The extra
+    exponent bit is what the format is for: it drops the smallest non-zero value from
+    `E4M3`'s 2^-9 to the subnormal 2^-17, so a block of small-magnitude elements gets
+    a scale that can actually represent it.
+
+  * Being a variant of `E4M3`, UE5M3 inherits its deviations from IEEE rather than the
+    IEEE reading of the same field widths: there are no infinities, and the all-ones
+    pattern is the one and only NaN. Having no sign bit, that is a single pattern
+    (`0xFF`) where `E4M3` has one per sign. The rest of the top binade therefore stays
+    finite, so the largest representable value is 114688 -- `E4M3`'s 448 carried up the
+    eight binades the extra exponent bit buys -- and not the 61440 an IEEE format of
+    this shape would stop at. Below that it is ordinary: zero, subnormals, and normals
+    all behave as IEEE says, with a bias of 15.
+
+  * Negative inputs are rejected rather than clamped. With no sign bit there is no
+    direction to saturate towards, and clamping would quietly turn the value positive;
+    this is the same call `E8M0` already makes, and it applies to a negative zero too.
+    Values above the range become NaN, following `E4M3`, which likewise has no infinity
+    to saturate to.
+
+  * All four GUIs offer the new format, in the "AI formats" group.
 
 ### Version 4.5, 2026-09-01
 
diff --git a/GUI/tclGUI/crackNum.tcl b/GUI/tclGUI/crackNum.tcl
--- a/GUI/tclGUI/crackNum.tcl
+++ b/GUI/tclGUI/crackNum.tcl
@@ -44,6 +44,7 @@
         {fe4m3    "FP8 (E4M3)"  fixed    e4m3}
         {fe5m2    "FP8 (E5M2)"  fixed    e5m2}
         {fe8m0    "FP8 (E8M0)"  fixed    e8m0}
+        {fue5m3   "FP8 (UE5M3)" fixed    ue5m3}
         {fbp      "Brain"       fixed    bp}
         {ftf32    "TF32"        fixed    tf32}
     }}
@@ -602,6 +603,7 @@
                 fp4     { set state(selection) ffp4 }
                 fp4e0m3 { set state(selection) ffp4e0m3 }
                 e8m0    { set state(selection) fe8m0 }
+                ue5m3   { set state(selection) fue5m3 }
                 default {
                     if {[regexp {^(\d+)\+(\d+)$} $v _ e s]} {
                         set state(selection) fcs
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -43,6 +43,7 @@
 -ffp4       FP4 (E2M1)                                  2             2
 -ffp4e0m3   FP4 (E0M3), sign-magnitude                  0             3
 -fe8m0      E8M0 (MX scale), exponent-only              8             0
+-fue5m3     UE5M3 (FP8 scale), unsigned                 5             4
 -fa+b       Arbitrary IEEE-754 float                    a             b
 ```
 
@@ -116,6 +117,29 @@
             Note: Original value of 10.0 was rounded to 8.0.
 ```
 
+### Example: Decode a UE5M3 FP8 scale
+`UE5M3` is `E4M3` with the sign bit -- which a scale never uses -- repurposed as the
+exponent's top bit. Like `E4M3` it has no infinities and exactly one `NaN`, so the top of
+the exponent range stays finite: this pattern is 65536, not the infinity an IEEE format of
+the same shape would read:
+```
+$ crackNum -fue5m3 0xF8
+Satisfiable. Model:
+  DECODED = 65536.0 :: UE5M3
+                  76543 210
+                  -E5-- S3-
+   Binary layout: 11111 000
+      Hex layout: F8
+       Precision: 5 exponent bits, 3 significand bits
+            Sign: Positive (always)
+        Exponent: 16 (Stored: 31, Bias: 15)
+  Classification: FP_NORMAL
+          Binary: 0b1p+16
+           Octal: 0o2p+15
+         Decimal: 65536.0
+             Hex: 0x1p+16
+```
+
 ### Example: Decode two half-precision lanes
 ```
 $ crackNum -l2 -fhp 32\'hfdc71fc6
@@ -202,6 +226,7 @@
       fp4: FP4 format (E2M1)      ( 2 +   2)
   fp4e0m3: FP4 format (E0M3)      ( 0 +   3)
      e8m0: FP8 format (MX scale)  ( 8 +   0)
+    ue5m3: FP8 format (Unsigned)  ( 5 +   4)
 
 Examples:
  Encoding:
@@ -218,6 +243,7 @@
    crackNum -ffp4     2.5                     -- encode as an FP4 (E2M1) float
    crackNum -ffp4e0m3 3.5                     -- encode as an FP4 (E0M3) sign-magnitude integer
    crackNum -fe8m0    2.5                     -- encode as an E8M0 MX scale (power of two)
+   crackNum -fue5m3   2.5                     -- encode as a UE5M3 FP8 scale (unsigned)
    crackNum -fsp      0x3.2p5                 -- encode as single-precision from hex-float
 
  Decoding:
@@ -231,6 +257,7 @@
    crackNum -ffp4     0b0111                  -- decode as an FP4 (E2M1) float
    crackNum -ffp4e0m3 0b1101                  -- decode as an FP4 (E0M3) sign-magnitude integer
    crackNum -fe8m0    0x7F                    -- decode as an E8M0 MX scale (power of two)
+   crackNum -fue5m3   0x78                    -- decode as a UE5M3 FP8 scale (unsigned)
    crackNum -l4 -fhp  64\'hbdffaaffdc71fc60   -- decode as half-precision float over 4 lanes using verilog notation
 
  GUI:
@@ -252,6 +279,10 @@
          so every value is a power of two, from 2^-127 to 2^127. It has no zero
          and no Inf, and 0xFF is its only NaN. Negative inputs are rejected;
          values outside the range saturate to the nearest end-point.
+       - UE5M3 is E4M3 with the sign bit repurposed as the exponent's top bit: 5
+         exponent bits and 3 significand bits, and no sign. Like E4M3 it has no
+         Inf, and 0xFF is its only NaN, so the range runs [0, 114688]. Negative
+         inputs are rejected, and values above the range become NaN.
    - For decoding:
        - Use hexadecimal (0x) binary (0b), or N'h (verilog) notation as input.
          Input must have one of these prefixes.
diff --git a/crackNum.cabal b/crackNum.cabal
--- a/crackNum.cabal
+++ b/crackNum.cabal
@@ -1,6 +1,6 @@
 Cabal-version      : 2.2
 Name               : crackNum
-Version            : 4.5
+Version            : 4.6
 Synopsis           : Crack various integer and floating-point data formats
 Description        : Crack IEEE-754 and other float formats and arbitrary sized words and integers, showing the layout.
                      Along with a command-line interface on any platform, native MacOS and Windows GUIs, a Tcl-based Linux GUI, and a browser front-end are available as well:
diff --git a/crackNum.vim b/crackNum.vim
--- a/crackNum.vim
+++ b/crackNum.vim
@@ -40,7 +40,7 @@
 " Used only when crackNum is too old to know --list-formats, or is not on the PATH.
 " Anything crackNum has learned since is picked up from the executable, not from here.
 let s:crackNumFallbackFormats = [ "hp", "bp", "tf32", "sp", "dp", "qp"
-                              \ , "e5m2", "e4m3", "fp4", "fp4e0m3", "e8m0"
+                              \ , "e5m2", "e4m3", "fp4", "fp4e0m3", "e8m0", "ue5m3"
                               \ ]
 
 " The formats the executable reports, as -f flags. Asking it keeps this list from
diff --git a/src/CrackNum/Decode.hs b/src/CrackNum/Decode.hs
--- a/src/CrackNum/Decode.hs
+++ b/src/CrackNum/Decode.hs
@@ -123,7 +123,8 @@
                      E4M3    -> de4m3 config allBits
                      FP4     -> dFP4  config allBits
                      FP4E0M3 -> decodeFP4E0M3 allBits
-                     E8M0    -> decodeE8M0 debug allBits
+                     E8M0    -> decodeE8M0  debug allBits
+                     UE5M3   -> decodeUE5M3 debug allBits
 
         dFloat :: [SBool] -> ConstraintSet
         dFloat  bs = do x <- sFloat "DECODED"
@@ -188,3 +189,9 @@
 decodeE8M0 :: Bool -> [Bool] -> IO ()
 decodeE8M0 debug bs@[_, _, _, _, _, _, _, _] = putStr $ unlines $ e8m0Layout debug "DECODED" (foldl (\sofar b -> 2 * sofar + (if b then 1 else 0)) 0 bs)
 decodeE8M0 _     bs                          = error $ "decodeE8M0: Unexpected bits: " ++ show bs   -- Can't happen; the caller checks the width
+
+-- | Decoding UE5M3: the byte is read straight off, five bits of exponent then three of
+-- significand, with no sign bit in the way.
+decodeUE5M3 :: Bool -> [Bool] -> IO ()
+decodeUE5M3 debug bs@[_, _, _, _, _, _, _, _] = putStr $ unlines $ ue5m3Layout debug "DECODED" (foldl (\sofar b -> 2 * sofar + (if b then 1 else 0)) 0 bs)
+decodeUE5M3 _     bs                          = error $ "decodeUE5M3: Unexpected bits: " ++ show bs   -- Can't happen; the caller checks the width
diff --git a/src/CrackNum/Encode.hs b/src/CrackNum/Encode.hs
--- a/src/CrackNum/Encode.hs
+++ b/src/CrackNum/Encode.hs
@@ -152,6 +152,8 @@
 
         ef E8M0    _ = encodeE8M0 debug rm inp
 
+        ef UE5M3   _ = encodeUE5M3 debug rm inp
+
 -- Encoding E4M3 is tricky, because of deviation from IEEE. So, we do a case analysis, mostly
 encodeE4M3 :: Bool -> RM -> String -> IO ()
 encodeE4M3 debug rm inp = case reads (fixup True inp) of
@@ -530,6 +532,95 @@
                  | isInfinite v || v > largest || v < smallest
                  = do putStrLn $ "            Note: Original value of " ++ show v ++ " is out of range, saturated to " ++ show t ++ "."
                       putStrLn   "                  The representable range is [2^-127, 2^127]."
+                 | v == t
+                 = exact
+                 | True
+                 = putStrLn $ "            Note: Original value of " ++ show v ++ " was rounded to " ++ show t ++ "."
+
+               exact = putStrLn $ "            Note: Conversion from " ++ show inp ++ " was exact. No rounding happened."
+
+-- | Encoding UE5M3. Every representable value is exact as a Double and the encodings run in
+-- increasing order, so we round by hand against the table rather than going through LibBF.
+-- We have to: the top seven encodings sit exactly where IEEE puts infinity and NaN, so no
+-- amount of IEEE rounding would ever land on them. Ties break on the parity of the encoding
+-- index, which for this format is precisely IEEE's ties-to-even -- stepping one encoding steps
+-- the significand by one, across binade boundaries included -- and is what 'encodeFP4' and
+-- 'encodeE8M0' already do.
+encodeUE5M3 :: Bool -> RM -> String -> IO ()
+encodeUE5M3 debug rm inp = case reads (fixup True inp) of
+                             [(v :: Double, "")] -> analyze v
+                             _                   -> -- maybe it's a hexfloat? As in encodeFP4, the catch must
+                                                    -- scope over the parse only: analyze can legitimately die,
+                                                    -- and die throws an exit-exception of its own.
+                                                    do let hr = readHexRational inp
+                                                       ok <- (rnf hr `seq` pure True)
+                                                               `C.catch` (\(_ :: C.SomeException) -> pure False)
+                                                       if ok then analyze (fromRational hr)
+                                                             else unrecognized inp
+ where largest :: Double
+       largest = last ue5m3Mags   -- 114688, the deviant encoding 0xFE
+
+       -- The one and only NaN: all ones. Being unsigned, UE5M3 has a single such pattern
+       -- where E4M3, which it otherwise follows, has one for each sign.
+       nanBits :: Int
+       nanBits = 0xFF
+
+       analyze :: Double -> IO ()
+       analyze v
+         -- NaN is representable, and uniquely so.
+         | isNaN v
+         = out nanBits
+         -- A negative is not an out-of-range magnitude: with no sign bit there is no direction
+         -- to saturate towards, and clamping would quietly make it positive. A negative zero is
+         -- still negative -- the same call 'encodeE8M0' makes.
+         | v < 0 || isNegativeZero v
+         = die [ "UE5M3 has no representation for negative values."
+               , "The representable range is [0, 114688], plus NaN."
+               ]
+         -- Having no infinity to saturate to, E4M3 turns whatever it cannot represent into NaN
+         -- rather than clamping; UE5M3 inherits that, and infinity is the limiting case of it.
+         | isInfinite v || v > largest
+         = out nanBits
+         | True
+         = out (roundMag v)
+        where out stored = do putStr $ unlines $ ue5m3Layout debug "ENCODED" stored
+                              trailer v stored
+
+       -- Round to the index of one of the representable magnitudes, honoring the rounding mode.
+       -- Every value reaching here is non-negative, so RTZ and RTN necessarily agree, as do RTP
+       -- and rounding away from zero.
+       roundMag :: Double -> Int
+       roundMag m
+         | e : _ <- [i | (i, mv) <- zip [0..] ue5m3Mags, mv == m]   -- Exactly representable
+         = e
+         | True
+         = case rm of
+             RTZ -> lo
+             RTN -> lo
+             RTP -> hi
+             RNE -> nearest (if even lo then lo else hi)
+             RNA -> nearest hi
+        where lo = last [i | (i, mv) <- zip [0..] ue5m3Mags, mv < m]
+              hi = lo + 1
+
+              -- Ties are broken by the given choice; note that comparing against the sum avoids
+              -- any rounding of its own, since all the values involved are exact.
+              nearest tie = case compare (2 * m) (ue5m3Mags !! lo + ue5m3Mags !! hi) of
+                              LT -> lo
+                              GT -> hi
+                              EQ -> tie
+
+       trailer :: Double -> Int -> IO ()
+       trailer v stored = do putStrLn $ "   Rounding mode: " ++ show rm
+                             note
+         where t = ue5m3Value stored
+
+               note
+                 | isNaN v
+                 = exact
+                 | isInfinite v || v > largest
+                 = do putStrLn $ "            Note: The input value " ++ show v ++ " is out of bounds, and hence becomes NaN."
+                      putStrLn   "                  The representable range is [0, 114688]."
                  | v == t
                  = exact
                  | True
diff --git a/src/CrackNum/Formats.hs b/src/CrackNum/Formats.hs
--- a/src/CrackNum/Formats.hs
+++ b/src/CrackNum/Formats.hs
@@ -50,6 +50,7 @@
             , ("fp4",     "FP4 format (E2M1)",      "( 2 +   2)", True )
             , ("fp4e0m3", "FP4 format (E0M3)",      "( 0 +   3)", True )
             , ("e8m0",    "FP8 format (MX scale)",  "( 8 +   0)", True )
+            , ("ue5m3",   "FP8 format (Unsigned)",  "( 5 +   4)", True )
             ]
 
 -- | The formats that can actually be named, i.e., everything but the arbitrary a+b
@@ -78,6 +79,7 @@
 getFP "fp4"     = Floating FP4
 getFP "fp4e0m3" = Floating FP4E0M3
 getFP "e8m0"    = Floating E8M0
+getFP "ue5m3"   = Floating UE5M3
 getFP ab        = case span isDigit ab of
                   (eb@(_:_), '+':r) -> case span isDigit r of
                                         (sp@(_:_), "") -> mkEBSB (read eb) (read sp)
diff --git a/src/CrackNum/Options.hs b/src/CrackNum/Options.hs
--- a/src/CrackNum/Options.hs
+++ b/src/CrackNum/Options.hs
@@ -87,6 +87,7 @@
                               , "   " ++ pn ++ " -ffp4     2.5                     -- encode as an FP4 (E2M1) float"
                               , "   " ++ pn ++ " -ffp4e0m3 3.5                     -- encode as an FP4 (E0M3) sign-magnitude integer"
                               , "   " ++ pn ++ " -fe8m0    2.5                     -- encode as an E8M0 MX scale (power of two)"
+                              , "   " ++ pn ++ " -fue5m3   2.5                     -- encode as a UE5M3 FP8 scale (unsigned)"
                               , "   " ++ pn ++ " -fsp      0x3.2p5                 -- encode as single-precision from hex-float"
                               , ""
                               , " Decoding:"
@@ -100,6 +101,7 @@
                               , "   " ++ pn ++ " -ffp4     0b0111                  -- decode as an FP4 (E2M1) float"
                               , "   " ++ pn ++ " -ffp4e0m3 0b1101                  -- decode as an FP4 (E0M3) sign-magnitude integer"
                               , "   " ++ pn ++ " -fe8m0    0x7F                    -- decode as an E8M0 MX scale (power of two)"
+                              , "   " ++ pn ++ " -fue5m3   0x78                    -- decode as a UE5M3 FP8 scale (unsigned)"
                               , "   " ++ pn ++ " -l4 -fhp  64\\'hbdffaaffdc71fc60   -- decode as half-precision float over 4 lanes using verilog notation"
                               , ""
                               , " GUI:"
@@ -121,6 +123,10 @@
                               , "         so every value is a power of two, from 2^-127 to 2^127. It has no zero"
                               , "         and no Inf, and 0xFF is its only NaN. Negative inputs are rejected;"
                               , "         values outside the range saturate to the nearest end-point."
+                              , "       - UE5M3 is E4M3 with the sign bit repurposed as the exponent\'s top bit: 5"
+                              , "         exponent bits and 3 significand bits, and no sign. Like E4M3 it has no"
+                              , "         Inf, and 0xFF is its only NaN, so the range runs [0, 114688]. Negative"
+                              , "         inputs are rejected, and values above the range become NaN."
                               , "   - For decoding:"
                               , "       - Use hexadecimal (0x) binary (0b), or N'h (verilog) notation as input."
                               , "         Input must have one of these prefixes."
diff --git a/src/CrackNum/Output.hs b/src/CrackNum/Output.hs
--- a/src/CrackNum/Output.hs
+++ b/src/CrackNum/Output.hs
@@ -16,15 +16,18 @@
 module CrackNum.Output(
      retype, printAs, modOut, isClassification, dropNaNUniquenessNote, canonicalNaN,
      ExtraE3M4(..), toD, inBases, fp4e0m3Layout, e8m0Bias, e8m0Value, e8m0Layout
+   , ue5m3Bias, ue5m3Value, ue5m3Mags, ue5m3IsDeviant, ue5m3Layout
    ) where
 
-import Data.Char (intToDigit, toUpper)
-import Data.List (intercalate, isInfixOf)
+import Data.Char (intToDigit, isSpace, toUpper)
+import Data.List (dropWhileEnd, intercalate, isInfixOf)
 
 import Numeric (showIntAtBase)
 
 import Data.SBV
 import qualified Data.SBV as SBV
+import Data.SBV.Float     (fpFromRawRep)
+import Data.SBV.Internals (SBV(..), SVal(..), CV(..), CVal(..))
 
 import CrackNum.Types
 
@@ -73,7 +76,7 @@
 isClassification = ("Classification:" `isInfixOf`)
 
 -- | SBV notes that a NaN's representation is not unique. That holds for IEEE formats,
--- but not for the ones here that have exactly one NaN pattern (E4M3 and E8M0), so drop
+-- but not for the ones here that have exactly one NaN pattern (E4M3, E8M0 and UE5M3), so drop
 -- the note for those rather than claim an ambiguity the format does not have.
 dropNaNUniquenessNote :: [String] -> [String]
 dropNaNUniquenessNote = filter (not . ("Representation for NaN's is not unique" `isInfixOf`))
@@ -186,3 +189,102 @@
         inBase b x = showIntAtBase b intToDigit x ""
 
         pad n x = replicate (n - length x) '0' ++ x
+
+-- | UE5M3 is the unsigned FP8 scale format proposed for FP4 microscaling. It is E4M3 with the
+-- sign bit -- which a scale, being non-negative, never uses -- repurposed as the exponent's
+-- top bit, giving 5 exponent bits and 3 significand bits in the same 8. Being a variant of
+-- E4M3 it inherits E4M3's deviations from IEEE: there are no infinities, and the all-ones
+-- pattern is the one and only NaN. Having no sign bit, that is a single pattern (0xFF) where
+-- E4M3 has two. The rest of the top binade therefore stays finite, so the largest value is
+-- 114688 rather than the 61440 an IEEE format with these field widths would stop at.
+ue5m3Bias :: Int
+ue5m3Bias = 15
+
+-- | The encodings where UE5M3 parts company with IEEE: 0xF8 to 0xFE would be infinity and
+-- NaN, but are read as ordinary finite numbers, 65536 through 114688. This is exactly E4M3's
+-- deviation -- its 256 through 448 -- carried up the eight binades the extra exponent bit buys.
+ue5m3IsDeviant :: Int -> Bool
+ue5m3IsDeviant b = b >= 0xF8 && b <= 0xFE
+
+-- | The value a UE5M3 encoding denotes. All 255 finite encodings are exactly representable as
+-- a Double -- the smallest is the subnormal 2^-17 and the largest is 114688 -- so 'encodeFloat'
+-- builds every one of them without rounding, which @2 **@ would not be guaranteed to do.
+ue5m3Value :: Int -> Double
+ue5m3Value 255 = 0/0
+ue5m3Value b   = case b `divMod` 8 of
+                   (0, m) -> encodeFloat (fromIntegral m)       (-17)      -- zero, then the subnormals
+                   (e, m) -> encodeFloat (fromIntegral (8 + m)) (e - 18)   -- the normals, implicit bit restored
+
+-- | Every finite UE5M3 magnitude, in increasing order. The index of each is precisely its
+-- encoding, which is what the encoder's rounding search relies on: stepping one encoding
+-- steps one representable value, so ties break on the parity of the index.
+ue5m3Mags :: [Double]
+ue5m3Mags = map ue5m3Value [0 .. 254]
+
+-- | Lay out a UE5M3 value. There is no 8-bit IEEE look-alike with five exponent bits to lean
+-- on -- adding the sign bit IEEE insists on would make it nine -- so the layout is built by
+-- hand, following the shape crackNum prints for the other formats. Everything from the
+-- precision down still comes from a look-alike, since that part describes the value rather
+-- than where its bits sit: 'FP 5 4' says exactly the right thing for the 249 ordinary
+-- encodings, including which of them are subnormal and which is NaN. Only its sign line has
+-- to be overridden, since it has a sign bit and UE5M3 does not.
+--
+-- The seven deviants have no float look-alike at all -- that is what makes them deviant -- so
+-- they take their value lines from the Double they are equal to, exactly as 'e8m0Layout' does
+-- and for the same reason. That prints them exactly, which matters here: their spacing is
+-- 8192, so a look-alike of UE5M3's own precision would render 65536 as "65540". E4M3 spells
+-- its deviants out exactly for this same reason, in 'inBases'.
+ue5m3Layout :: Bool -> String -> Int -> [String]
+ue5m3Layout debug tag stored =
+     [ "Satisfiable. Model:"
+     , "  " ++ tag ++ " = " ++ valStr ++ " :: " ++ show UE5M3
+     , "                  76543 210"
+     , "                  -E5-- S3-"
+     , "   Binary layout: " ++ pad 5 (inBase 2 e) ++ " " ++ pad 3 (inBase 2 m)
+     , "      Hex layout: " ++ map toUpper (pad 2 (inBase 16 stored))
+     ]
+  ++ dropNaNUniquenessNote body
+  where (e, m) = stored `divMod` 8
+
+        -- How the value renders on the model line, and the lines describing it. A Double knows
+        -- nothing of UE5M3's fields, so for a deviant the three lines between the layout and
+        -- the classification are written out here rather than taken from it.
+        (valStr, body)
+          | ue5m3IsDeviant stored
+          = ( show v
+            , [ "       Precision: 5 exponent bits, 3 significand bits"
+              , "            Sign: " ++ alwaysPositive
+              , "        Exponent: 16 (Stored: 31, Bias: " ++ show ue5m3Bias ++ ")"
+              ]
+              ++ dropWhile (not . isClassification) (cracked (literal v :: SDouble))
+            )
+          | True
+          = ( untype (show lookAlike)
+            , map fixSign $ dropWhile (not . ("Precision:" `isInfixOf`)) (cracked lookAlike)
+            )
+          where v         = ue5m3Value stored
+                lookAlike = mkFP 5 4 (fromIntegral e) (fromIntegral m) :: SFloatingPoint 5 4
+
+        cracked :: SBV a -> [String]
+        cracked = lines . SBV.crack debug
+
+        -- NB. There is no sign bit: bit 7 is the exponent's MSB. We keep the line so the block
+        -- has the same shape as every other format's, but say outright that it can never read
+        -- anything else -- the same thing 'e8m0Layout' does, for the same reason.
+        alwaysPositive = "Positive (always)"
+
+        fixSign l | "Sign:" `isInfixOf` l = takeWhile (/= ':') l ++ ": " ++ alwaysPositive
+                  | True                  = l
+
+        -- 'show' on a look-alike appends its own type, which is not the one the user asked for.
+        untype = dropWhileEnd isSpace . takeWhile (/= ':')
+
+        inBase b x = showIntAtBase b intToDigit x ""
+
+        pad n x = replicate (n - length x) '0' ++ x
+
+-- | A concrete float with the given field widths and stored fields, and a zero sign. Used only
+-- as a stand-in for UE5M3, which has no look-alike of its own.
+mkFP :: Int -> Int -> Integer -> Integer -> SBV a
+mkFP eb sb e m = SBV (SVal k (Left (CV k (CFP (fpFromRawRep False (e, eb) (m, sb))))))
+  where k = KFP eb sb
diff --git a/src/CrackNum/TestSuite.hs b/src/CrackNum/TestSuite.hs
--- a/src/CrackNum/TestSuite.hs
+++ b/src/CrackNum/TestSuite.hs
@@ -176,6 +176,41 @@
             | rm           <- ["RNE", "RNA", "RTP", "RTN", "RTZ"]
             ,  i :: Double <- [0.75, 1.5, 3, 6]
             ]
+          , testGroup "EncodeUE5M3" [
+               gold "encodeUE5M3_nan"     "-fue5m3    nan"        -- Representable, and uniquely so
+             , gold "encodeUE5M3_+inf"    "-fue5m3    inf"        -- No Inf to saturate to, so it becomes NaN
+             , gold "encodeUE5M3_-inf"    "-fue5m3 -- -inf"       -- Negative: rejected before the range check
+             , gold "encodeUE5M3_neg"     "-fue5m3 -- -5"
+             , gold "encodeUE5M3_zero1"   "-fue5m3 --  0"         -- Unlike E8M0, this format does have a zero
+             , gold "encodeUE5M3_zero2"   "-fue5m3 --  -0"        -- But a negative zero is still negative
+             , gold "encodeUE5M3_one"     "-fue5m3 --  1"
+             , gold "encodeUE5M3_exact"   "-fue5m3 --  2.5"
+             , gold "encodeUE5M3_sub"     "-fue5m3 --  0x1p-17"   -- The smallest non-zero value there is
+             , gold "encodeUE5M3_subrnd"  "-fue5m3 --  1e-10"     -- Under it, so rounds away to zero
+             , gold "encodeUE5M3_ieeemax" "-fue5m3 --  61440"     -- The largest value IEEE would have stopped at
+             , gold "encodeUE5M3_ieeernd" "-fue5m3 --  61441"     -- IEEE would overflow here; UE5M3 does not
+             , gold "encodeUE5M3_dev"     "-fue5m3 --  65536"     -- First of the seven that deviate
+             , gold "encodeUE5M3_max"     "-fue5m3 --  114688"    -- Last of them, and the largest value
+             , gold "encodeUE5M3_oob"     "-fue5m3 --  114689"    -- Over the top: NaN, following E4M3
+             , gold "encodeUE5M3_hex"     "-fue5m3 --  0x1.8p1"
+            ]
+          -- Every value that sits exactly half-way between two representable magnitudes, over
+          -- all rounding modes. These pin down the RNE tie rule where it is easiest to get
+          -- wrong: at the zero/subnormal boundary, across a binade, and -- for the last two --
+          -- across the point where UE5M3 parts company with IEEE and its top seven encodings
+          -- become ordinary numbers rather than infinity and NaN. All values are positive;
+          -- negatives are rejected outright.
+          , testGroup "EncodeUE5M3Ties" [
+               gold ("encodeUE5M3_tie_" ++ rm ++ "_" ++ nm) ("-fue5m3 -r" ++ rm ++ " -- " ++ v)
+            | rm      <- ["RNE", "RNA", "RTP", "RTN", "RTZ"]
+            , (nm, v) <- [ ("sub0",  "0x1p-18")   -- Between zero and the smallest subnormal
+                         , ("sub1",  "0x3p-18")   -- Between the two smallest subnormals
+                         , ("norm",  "1.0625")
+                         , ("binade","1.9375")    -- Straddles a binade boundary
+                         , ("dev0",  "63488")     -- Straddles the last IEEE-shaped value
+                         , ("dev1",  "69632")
+                         ]
+            ]
           , testGroup "Decode" [
               gold "decode0" "-i4       0b0110"
             , gold "decode1" "-w4       0xE"
@@ -243,6 +278,24 @@
                       , "80"
                       , "FD"
                       , "FE"     -- Largest: 2^127
+                      , "FF"     -- NaN, and the only one
+                      ]
+            ]
+          -- UE5M3 has 256 patterns, so we take a spread the way DecodeE8M0 does, covering
+          -- each structural case: the zero, both ends of the subnormals, the first normal,
+          -- the unit value, the last IEEE-shaped value, the deviants either side, and the
+          -- sole NaN.
+          , testGroup "DecodeUE5M3" [
+               gold ("decodeUE5M3_" ++ bits) ("-fue5m3 0x" ++ bits)
+            | bits <- [ "00"     -- Zero
+                      , "01"     -- Smallest subnormal: 2^-17
+                      , "07"     -- Largest subnormal
+                      , "08"     -- Smallest normal
+                      , "78"     -- 1.0
+                      , "F7"     -- 61440: the largest an IEEE format of this shape would reach
+                      , "F8"     -- 65536: IEEE would call this infinity
+                      , "FB"     -- 90112: IEEE would call this NaN
+                      , "FE"     -- 114688, the largest value
                       , "FF"     -- NaN, and the only one
                       ]
             ]
diff --git a/src/CrackNum/Types.hs b/src/CrackNum/Types.hs
--- a/src/CrackNum/Types.hs
+++ b/src/CrackNum/Types.hs
@@ -29,6 +29,7 @@
         | FP4         -- NVIDIA FP4 (E2M1) format with no infinities and no NaNs
         | FP4E0M3     -- 4-bit sign-magnitude integer format; no exponent at all
         | E8M0        -- OCP MX scale format; no sign and no significand at all
+        | UE5M3       -- Unsigned FP8 scale format; E4M3 with the sign bit given to the exponent
         deriving (Show, Eq)
 
 -- | How many bits does this float occupy
@@ -41,6 +42,7 @@
 fpSize FP4      = 4
 fpSize FP4E0M3  = 4
 fpSize E8M0     = 8
+fpSize UE5M3    = 8
 
 -- | Kinds of numbers we understand
 data NKind = SInt   Int -- ^ Signed   integer of n bits
