<!DOCTYPE html>

<html lang="en">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="mobile-web-app-capable" content="yes">
    <title>
        Atomic floating-point min/max
    </title>

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha256-916EbMg70RQy9LHiGkXzG8hSg9EdNy97GazNG/aiY1w=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css" integrity="sha256-3iu9jgsy9TpTwXKb7bNQzqWekRX7pPK+2OLj3R922fo=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/3.5.0/octicons.min.css" integrity="sha256-QiWfLIsCT02Sdwkogf6YMiQlj4NE84MKkzEMkZnMGdg=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css" integrity="sha256-vtR0hSWRc3Tb26iuN2oZHt3KRUomwTufNIf5/4oeCyg=" crossorigin="anonymous" />
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@hackmd/emojify.js@2.1.0/dist/css/basic/emojify.min.css" integrity="sha256-UOrvMOsSDSrW6szVLe8ZDZezBxh5IoIfgTwdNDgTjiU=" crossorigin="anonymous" />
    <style>
        @import url(https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i|Source+Code+Pro:300,400,500|Source+Sans+Pro:300,300i,400,400i,600,600i|Source+Serif+Pro&subset=latin-ext);
/*!
  Theme: GitHub
  Description: Light theme as seen on github.com
  Author: github.com
  Maintainer: @Hirse
  Updated: 2021-05-15

  Outdated base version: https://github.com/primer/github-syntax-light
  Current colors taken from GitHub's CSS
*/:root[theme=light] :not([theme])>*>.markdown-body .hljs-doctag,:root[theme=light] :not([theme])>*>.markdown-body .hljs-keyword,:root[theme=light] :not([theme])>*>.markdown-body .hljs-meta .hljs-keyword,:root[theme=light] :not([theme])>*>.markdown-body .hljs-template-tag,:root[theme=light] :not([theme])>*>.markdown-body .hljs-template-variable,:root[theme=light] :not([theme])>*>.markdown-body .hljs-type,:root[theme=light] :not([theme])>*>.markdown-body .hljs-variable.language_,:root[theme] [theme=light] .markdown-body .hljs-doctag,:root[theme] [theme=light] .markdown-body .hljs-keyword,:root[theme] [theme=light] .markdown-body .hljs-meta .hljs-keyword,:root[theme] [theme=light] .markdown-body .hljs-template-tag,:root[theme] [theme=light] .markdown-body .hljs-template-variable,:root[theme] [theme=light] .markdown-body .hljs-type,:root[theme] [theme=light] .markdown-body .hljs-variable.language_{color:#d73a49}:root[theme=light] :not([theme])>*>.markdown-body .hljs-title,:root[theme=light] :not([theme])>*>.markdown-body .hljs-title.class_,:root[theme=light] :not([theme])>*>.markdown-body .hljs-title.class_.inherited__,:root[theme=light] :not([theme])>*>.markdown-body .hljs-title.function_,:root[theme] [theme=light] .markdown-body .hljs-title,:root[theme] [theme=light] .markdown-body .hljs-title.class_,:root[theme] [theme=light] .markdown-body .hljs-title.class_.inherited__,:root[theme] [theme=light] .markdown-body .hljs-title.function_{color:#6f42c1}:root[theme=light] :not([theme])>*>.markdown-body .hljs-attr,:root[theme=light] :not([theme])>*>.markdown-body .hljs-attribute,:root[theme=light] :not([theme])>*>.markdown-body .hljs-literal,:root[theme=light] :not([theme])>*>.markdown-body .hljs-meta,:root[theme=light] :not([theme])>*>.markdown-body .hljs-number,:root[theme=light] :not([theme])>*>.markdown-body .hljs-operator,:root[theme=light] :not([theme])>*>.markdown-body .hljs-selector-attr,:root[theme=light] :not([theme])>*>.markdown-body .hljs-selector-class,:root[theme=light] :not([theme])>*>.markdown-body .hljs-selector-id,:root[theme=light] :not([theme])>*>.markdown-body .hljs-variable,:root[theme] [theme=light] .markdown-body .hljs-attr,:root[theme] [theme=light] .markdown-body .hljs-attribute,:root[theme] [theme=light] .markdown-body .hljs-literal,:root[theme] [theme=light] .markdown-body .hljs-meta,:root[theme] [theme=light] .markdown-body .hljs-number,:root[theme] [theme=light] .markdown-body .hljs-operator,:root[theme] [theme=light] .markdown-body .hljs-selector-attr,:root[theme] [theme=light] .markdown-body .hljs-selector-class,:root[theme] [theme=light] .markdown-body .hljs-selector-id,:root[theme] [theme=light] .markdown-body .hljs-variable{color:#005cc5}:root[theme=light] :not([theme])>*>.markdown-body .hljs-meta .hljs-string,:root[theme=light] :not([theme])>*>.markdown-body .hljs-regexp,:root[theme=light] :not([theme])>*>.markdown-body .hljs-string,:root[theme] [theme=light] .markdown-body .hljs-meta .hljs-string,:root[theme] [theme=light] .markdown-body .hljs-regexp,:root[theme] [theme=light] .markdown-body .hljs-string{color:#032f62}:root[theme=light] :not([theme])>*>.markdown-body .hljs-built_in,:root[theme=light] :not([theme])>*>.markdown-body .hljs-symbol,:root[theme] [theme=light] .markdown-body .hljs-built_in,:root[theme] [theme=light] .markdown-body .hljs-symbol{color:#e36209}:root[theme=light] :not([theme])>*>.markdown-body .hljs-code,:root[theme=light] :not([theme])>*>.markdown-body .hljs-comment,:root[theme=light] :not([theme])>*>.markdown-body .hljs-formula,:root[theme] [theme=light] .markdown-body .hljs-code,:root[theme] [theme=light] .markdown-body .hljs-comment,:root[theme] [theme=light] .markdown-body .hljs-formula{color:#6a737d}:root[theme=light] :not([theme])>*>.markdown-body .hljs-name,:root[theme=light] :not([theme])>*>.markdown-body .hljs-quote,:root[theme=light] :not([theme])>*>.markdown-body .hljs-selector-pseudo,:root[theme=light] :not([theme])>*>.markdown-body .hljs-selector-tag,:root[theme] [theme=light] .markdown-body .hljs-name,:root[theme] [theme=light] .markdown-body .hljs-quote,:root[theme] [theme=light] .markdown-body .hljs-selector-pseudo,:root[theme] [theme=light] .markdown-body .hljs-selector-tag{color:#22863a}:root[theme=light] :not([theme])>*>.markdown-body .hljs-subst,:root[theme] [theme=light] .markdown-body .hljs-subst{color:#24292e}:root[theme=light] :not([theme])>*>.markdown-body .hljs-section,:root[theme] [theme=light] .markdown-body .hljs-section{color:#005cc5;font-weight:700}:root[theme=light] :not([theme])>*>.markdown-body .hljs-bullet,:root[theme] [theme=light] .markdown-body .hljs-bullet{color:#735c0f}:root[theme=light] :not([theme])>*>.markdown-body .hljs-emphasis,:root[theme] [theme=light] .markdown-body .hljs-emphasis{color:#24292e;font-style:italic}:root[theme=light] :not([theme])>*>.markdown-body .hljs-strong,:root[theme] [theme=light] .markdown-body .hljs-strong{color:#24292e;font-weight:700}:root[theme=light] :not([theme])>*>.markdown-body .hljs-addition,:root[theme] [theme=light] .markdown-body .hljs-addition{background-color:#f0fff4;color:#22863a}:root[theme=light] :not([theme])>*>.markdown-body .hljs-deletion,:root[theme] [theme=light] .markdown-body .hljs-deletion{background-color:#ffeef0;color:#b31d28}

/*!
  Theme: GitHub Dark Dimmed
  Description: Dark dimmed theme as seen on github.com
  Author: github.com
  Maintainer: @Hirse
  Updated: 2021-05-15

  Colors taken from GitHub's CSS
*/:root[theme=dark] :not([theme])>*>.markdown-body .hljs-doctag,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-keyword,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-meta .hljs-keyword,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-template-tag,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-template-variable,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-type,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-variable.language_,:root[theme] [theme=dark] .markdown-body .hljs-doctag,:root[theme] [theme=dark] .markdown-body .hljs-keyword,:root[theme] [theme=dark] .markdown-body .hljs-meta .hljs-keyword,:root[theme] [theme=dark] .markdown-body .hljs-template-tag,:root[theme] [theme=dark] .markdown-body .hljs-template-variable,:root[theme] [theme=dark] .markdown-body .hljs-type,:root[theme] [theme=dark] .markdown-body .hljs-variable.language_{color:#f47067}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-title,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-title.class_,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-title.class_.inherited__,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-title.function_,:root[theme] [theme=dark] .markdown-body .hljs-title,:root[theme] [theme=dark] .markdown-body .hljs-title.class_,:root[theme] [theme=dark] .markdown-body .hljs-title.class_.inherited__,:root[theme] [theme=dark] .markdown-body .hljs-title.function_{color:#dcbdfb}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-attr,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-attribute,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-literal,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-meta,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-number,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-operator,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-selector-attr,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-selector-class,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-selector-id,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-variable,:root[theme] [theme=dark] .markdown-body .hljs-attr,:root[theme] [theme=dark] .markdown-body .hljs-attribute,:root[theme] [theme=dark] .markdown-body .hljs-literal,:root[theme] [theme=dark] .markdown-body .hljs-meta,:root[theme] [theme=dark] .markdown-body .hljs-number,:root[theme] [theme=dark] .markdown-body .hljs-operator,:root[theme] [theme=dark] .markdown-body .hljs-selector-attr,:root[theme] [theme=dark] .markdown-body .hljs-selector-class,:root[theme] [theme=dark] .markdown-body .hljs-selector-id,:root[theme] [theme=dark] .markdown-body .hljs-variable{color:#6cb6ff}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-meta .hljs-string,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-regexp,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-string,:root[theme] [theme=dark] .markdown-body .hljs-meta .hljs-string,:root[theme] [theme=dark] .markdown-body .hljs-regexp,:root[theme] [theme=dark] .markdown-body .hljs-string{color:#96d0ff}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-built_in,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-symbol,:root[theme] [theme=dark] .markdown-body .hljs-built_in,:root[theme] [theme=dark] .markdown-body .hljs-symbol{color:#f69d50}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-code,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-comment,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-formula,:root[theme] [theme=dark] .markdown-body .hljs-code,:root[theme] [theme=dark] .markdown-body .hljs-comment,:root[theme] [theme=dark] .markdown-body .hljs-formula{color:#768390}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-name,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-quote,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-selector-pseudo,:root[theme=dark] :not([theme])>*>.markdown-body .hljs-selector-tag,:root[theme] [theme=dark] .markdown-body .hljs-name,:root[theme] [theme=dark] .markdown-body .hljs-quote,:root[theme] [theme=dark] .markdown-body .hljs-selector-pseudo,:root[theme] [theme=dark] .markdown-body .hljs-selector-tag{color:#8ddb8c}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-subst,:root[theme] [theme=dark] .markdown-body .hljs-subst{color:#adbac7}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-section,:root[theme] [theme=dark] .markdown-body .hljs-section{color:#316dca;font-weight:700}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-bullet,:root[theme] [theme=dark] .markdown-body .hljs-bullet{color:#eac55f}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-emphasis,:root[theme] [theme=dark] .markdown-body .hljs-emphasis{color:#adbac7;font-style:italic}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-strong,:root[theme] [theme=dark] .markdown-body .hljs-strong{color:#adbac7;font-weight:700}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-addition,:root[theme] [theme=dark] .markdown-body .hljs-addition{background-color:#1b4721;color:#b4f1b4}:root[theme=dark] :not([theme])>*>.markdown-body .hljs-deletion,:root[theme] [theme=dark] .markdown-body .hljs-deletion{background-color:#78191b;color:#ffd8d3}:root[theme=dark] :not([theme])>*>.markdown-body code[class*=language-],:root[theme=dark] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=dark] .markdown-body code[class*=language-],:root[theme] [theme=dark] .markdown-body pre[class*=language-]{word-wrap:normal;background:none;color:#ccc;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;-webkit-hyphens:none;hyphens:none;line-height:1.5;tab-size:4;text-align:left;white-space:pre;word-break:normal;word-spacing:normal}:root[theme=dark] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=dark] .markdown-body pre[class*=language-]{margin:.5em 0;overflow:auto;padding:1em}:root[theme=dark] :not([theme])>*>.markdown-body :not(pre)>code[class*=language-],:root[theme=dark] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=dark] .markdown-body :not(pre)>code[class*=language-],:root[theme] [theme=dark] .markdown-body pre[class*=language-]{background:#2d2d2d}:root[theme=dark] :not([theme])>*>.markdown-body :not(pre)>code[class*=language-],:root[theme] [theme=dark] .markdown-body :not(pre)>code[class*=language-]{border-radius:.3em;padding:.1em;white-space:normal}:root[theme=dark] :not([theme])>*>.markdown-body .token.block-comment,:root[theme=dark] :not([theme])>*>.markdown-body .token.cdata,:root[theme=dark] :not([theme])>*>.markdown-body .token.comment,:root[theme=dark] :not([theme])>*>.markdown-body .token.doctype,:root[theme=dark] :not([theme])>*>.markdown-body .token.prolog,:root[theme] [theme=dark] .markdown-body .token.block-comment,:root[theme] [theme=dark] .markdown-body .token.cdata,:root[theme] [theme=dark] .markdown-body .token.comment,:root[theme] [theme=dark] .markdown-body .token.doctype,:root[theme] [theme=dark] .markdown-body .token.prolog{color:#999}:root[theme=dark] :not([theme])>*>.markdown-body .token.punctuation,:root[theme] [theme=dark] .markdown-body .token.punctuation{color:#ccc}:root[theme=dark] :not([theme])>*>.markdown-body .token.attr-name,:root[theme=dark] :not([theme])>*>.markdown-body .token.deleted,:root[theme=dark] :not([theme])>*>.markdown-body .token.namespace,:root[theme=dark] :not([theme])>*>.markdown-body .token.tag,:root[theme] [theme=dark] .markdown-body .token.attr-name,:root[theme] [theme=dark] .markdown-body .token.deleted,:root[theme] [theme=dark] .markdown-body .token.namespace,:root[theme] [theme=dark] .markdown-body .token.tag{color:#e2777a}:root[theme=dark] :not([theme])>*>.markdown-body .token.function-name,:root[theme] [theme=dark] .markdown-body .token.function-name{color:#6196cc}:root[theme=dark] :not([theme])>*>.markdown-body .token.boolean,:root[theme=dark] :not([theme])>*>.markdown-body .token.function,:root[theme=dark] :not([theme])>*>.markdown-body .token.number,:root[theme] [theme=dark] .markdown-body .token.boolean,:root[theme] [theme=dark] .markdown-body .token.function,:root[theme] [theme=dark] .markdown-body .token.number{color:#f08d49}:root[theme=dark] :not([theme])>*>.markdown-body .token.class-name,:root[theme=dark] :not([theme])>*>.markdown-body .token.constant,:root[theme=dark] :not([theme])>*>.markdown-body .token.property,:root[theme=dark] :not([theme])>*>.markdown-body .token.symbol,:root[theme] [theme=dark] .markdown-body .token.class-name,:root[theme] [theme=dark] .markdown-body .token.constant,:root[theme] [theme=dark] .markdown-body .token.property,:root[theme] [theme=dark] .markdown-body .token.symbol{color:#f8c555}:root[theme=dark] :not([theme])>*>.markdown-body .token.atrule,:root[theme=dark] :not([theme])>*>.markdown-body .token.builtin,:root[theme=dark] :not([theme])>*>.markdown-body .token.important,:root[theme=dark] :not([theme])>*>.markdown-body .token.keyword,:root[theme=dark] :not([theme])>*>.markdown-body .token.selector,:root[theme] [theme=dark] .markdown-body .token.atrule,:root[theme] [theme=dark] .markdown-body .token.builtin,:root[theme] [theme=dark] .markdown-body .token.important,:root[theme] [theme=dark] .markdown-body .token.keyword,:root[theme] [theme=dark] .markdown-body .token.selector{color:#cc99cd}:root[theme=dark] :not([theme])>*>.markdown-body .token.attr-value,:root[theme=dark] :not([theme])>*>.markdown-body .token.char,:root[theme=dark] :not([theme])>*>.markdown-body .token.regex,:root[theme=dark] :not([theme])>*>.markdown-body .token.string,:root[theme=dark] :not([theme])>*>.markdown-body .token.variable,:root[theme] [theme=dark] .markdown-body .token.attr-value,:root[theme] [theme=dark] .markdown-body .token.char,:root[theme] [theme=dark] .markdown-body .token.regex,:root[theme] [theme=dark] .markdown-body .token.string,:root[theme] [theme=dark] .markdown-body .token.variable{color:#7ec699}:root[theme=dark] :not([theme])>*>.markdown-body .token.entity,:root[theme=dark] :not([theme])>*>.markdown-body .token.operator,:root[theme=dark] :not([theme])>*>.markdown-body .token.url,:root[theme] [theme=dark] .markdown-body .token.entity,:root[theme] [theme=dark] .markdown-body .token.operator,:root[theme] [theme=dark] .markdown-body .token.url{color:#67cdcc}:root[theme=dark] :not([theme])>*>.markdown-body .token.bold,:root[theme=dark] :not([theme])>*>.markdown-body .token.important,:root[theme] [theme=dark] .markdown-body .token.bold,:root[theme] [theme=dark] .markdown-body .token.important{font-weight:700}:root[theme=dark] :not([theme])>*>.markdown-body .token.italic,:root[theme] [theme=dark] .markdown-body .token.italic{font-style:italic}:root[theme=dark] :not([theme])>*>.markdown-body .token.entity,:root[theme] [theme=dark] .markdown-body .token.entity{cursor:help}:root[theme=dark] :not([theme])>*>.markdown-body .token.inserted,:root[theme] [theme=dark] .markdown-body .token.inserted{color:green}:root[theme=light] :not([theme])>*>.markdown-body code[class*=language-],:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=light] .markdown-body code[class*=language-],:root[theme] [theme=light] .markdown-body pre[class*=language-]{word-wrap:normal;background:none;color:#000;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;-webkit-hyphens:none;hyphens:none;line-height:1.5;tab-size:4;text-align:left;text-shadow:0 1px #fff;white-space:pre;word-break:normal;word-spacing:normal}:root[theme=light] :not([theme])>*>.markdown-body code[class*=language-] ::selection,:root[theme=light] :not([theme])>*>.markdown-body code[class*=language-]::selection,:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-] ::selection,:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-]::selection,:root[theme] [theme=light] .markdown-body code[class*=language-] ::selection,:root[theme] [theme=light] .markdown-body code[class*=language-]::selection,:root[theme] [theme=light] .markdown-body pre[class*=language-] ::selection,:root[theme] [theme=light] .markdown-body pre[class*=language-]::selection{background:#b3d4fc;text-shadow:none}:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=light] .markdown-body pre[class*=language-]{margin:.5em 0;overflow:auto;padding:1em}:root[theme=light] :not([theme])>*>.markdown-body :not(pre)>code[class*=language-],:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=light] .markdown-body :not(pre)>code[class*=language-],:root[theme] [theme=light] .markdown-body pre[class*=language-]{background:#f5f2f0}:root[theme=light] :not([theme])>*>.markdown-body :not(pre)>code[class*=language-],:root[theme] [theme=light] .markdown-body :not(pre)>code[class*=language-]{border-radius:.3em;padding:.1em;white-space:normal}:root[theme=light] :not([theme])>*>.markdown-body .token.cdata,:root[theme=light] :not([theme])>*>.markdown-body .token.comment,:root[theme=light] :not([theme])>*>.markdown-body .token.doctype,:root[theme=light] :not([theme])>*>.markdown-body .token.prolog,:root[theme] [theme=light] .markdown-body .token.cdata,:root[theme] [theme=light] .markdown-body .token.comment,:root[theme] [theme=light] .markdown-body .token.doctype,:root[theme] [theme=light] .markdown-body .token.prolog{color:#708090}:root[theme=light] :not([theme])>*>.markdown-body .token.punctuation,:root[theme] [theme=light] .markdown-body .token.punctuation{color:#999}:root[theme=light] :not([theme])>*>.markdown-body .token.namespace,:root[theme] [theme=light] .markdown-body .token.namespace{opacity:.7}:root[theme=light] :not([theme])>*>.markdown-body .token.boolean,:root[theme=light] :not([theme])>*>.markdown-body .token.constant,:root[theme=light] :not([theme])>*>.markdown-body .token.deleted,:root[theme=light] :not([theme])>*>.markdown-body .token.number,:root[theme=light] :not([theme])>*>.markdown-body .token.property,:root[theme=light] :not([theme])>*>.markdown-body .token.symbol,:root[theme=light] :not([theme])>*>.markdown-body .token.tag,:root[theme] [theme=light] .markdown-body .token.boolean,:root[theme] [theme=light] .markdown-body .token.constant,:root[theme] [theme=light] .markdown-body .token.deleted,:root[theme] [theme=light] .markdown-body .token.number,:root[theme] [theme=light] .markdown-body .token.property,:root[theme] [theme=light] .markdown-body .token.symbol,:root[theme] [theme=light] .markdown-body .token.tag{color:#905}:root[theme=light] :not([theme])>*>.markdown-body .token.attr-name,:root[theme=light] :not([theme])>*>.markdown-body .token.builtin,:root[theme=light] :not([theme])>*>.markdown-body .token.char,:root[theme=light] :not([theme])>*>.markdown-body .token.inserted,:root[theme=light] :not([theme])>*>.markdown-body .token.selector,:root[theme=light] :not([theme])>*>.markdown-body .token.string,:root[theme] [theme=light] .markdown-body .token.attr-name,:root[theme] [theme=light] .markdown-body .token.builtin,:root[theme] [theme=light] .markdown-body .token.char,:root[theme] [theme=light] .markdown-body .token.inserted,:root[theme] [theme=light] .markdown-body .token.selector,:root[theme] [theme=light] .markdown-body .token.string{color:#690}:root[theme=light] :not([theme])>*>.markdown-body .language-css .token.string,:root[theme=light] :not([theme])>*>.markdown-body .style .token.string,:root[theme=light] :not([theme])>*>.markdown-body .token.entity,:root[theme=light] :not([theme])>*>.markdown-body .token.operator,:root[theme=light] :not([theme])>*>.markdown-body .token.url,:root[theme] [theme=light] .markdown-body .language-css .token.string,:root[theme] [theme=light] .markdown-body .style .token.string,:root[theme] [theme=light] .markdown-body .token.entity,:root[theme] [theme=light] .markdown-body .token.operator,:root[theme] [theme=light] .markdown-body .token.url{background:#ffffff80;color:#9a6e3a}:root[theme=light] :not([theme])>*>.markdown-body .token.atrule,:root[theme=light] :not([theme])>*>.markdown-body .token.attr-value,:root[theme=light] :not([theme])>*>.markdown-body .token.keyword,:root[theme] [theme=light] .markdown-body .token.atrule,:root[theme] [theme=light] .markdown-body .token.attr-value,:root[theme] [theme=light] .markdown-body .token.keyword{color:#07a}:root[theme=light] :not([theme])>*>.markdown-body .token.class-name,:root[theme=light] :not([theme])>*>.markdown-body .token.function,:root[theme] [theme=light] .markdown-body .token.class-name,:root[theme] [theme=light] .markdown-body .token.function{color:#dd4a68}:root[theme=light] :not([theme])>*>.markdown-body .token.important,:root[theme=light] :not([theme])>*>.markdown-body .token.regex,:root[theme=light] :not([theme])>*>.markdown-body .token.variable,:root[theme] [theme=light] .markdown-body .token.important,:root[theme] [theme=light] .markdown-body .token.regex,:root[theme] [theme=light] .markdown-body .token.variable{color:#e90}:root[theme=light] :not([theme])>*>.markdown-body .token.bold,:root[theme=light] :not([theme])>*>.markdown-body .token.important,:root[theme] [theme=light] .markdown-body .token.bold,:root[theme] [theme=light] .markdown-body .token.important{font-weight:700}:root[theme=light] :not([theme])>*>.markdown-body .token.italic,:root[theme] [theme=light] .markdown-body .token.italic{font-style:italic}:root[theme=light] :not([theme])>*>.markdown-body .token.entity,:root[theme] [theme=light] .markdown-body .token.entity{cursor:help}@media print{:root[theme=light] :not([theme])>*>.markdown-body code[class*=language-],:root[theme=light] :not([theme])>*>.markdown-body pre[class*=language-],:root[theme] [theme=light] .markdown-body code[class*=language-],:root[theme] [theme=light] .markdown-body pre[class*=language-]{text-shadow:none}}.markdown-body{word-wrap:break-word;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;font-size:16px;line-height:1.5}.markdown-body:after,.markdown-body:before{content:"";display:table}.markdown-body:after{clear:both}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:#c00}.markdown-body .anchor{float:left;line-height:1;margin-left:-20px;padding-right:4px}.markdown-body .anchor:focus{outline:none}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-bottom:16px;margin-top:0}.markdown-body hr{background-color:#e7e7e7;border:0;height:.25em;margin:24px 0;padding:0}.markdown-body blockquote{border-left:.25em solid #ddd;color:#777;font-size:16px;padding:0 1em}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body kbd,.popover kbd{background-color:#fcfcfc;border:1px solid;border-color:#ccc #ccc #bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb;color:#555;display:inline-block;font-size:11px;line-height:10px;padding:3px 5px;vertical-align:middle}.markdown-body .loweralpha{list-style-type:lower-alpha}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{font-weight:600;line-height:1.25;margin-bottom:16px;margin-top:24px}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#000;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit}.markdown-body h1{font-size:2em}.markdown-body h1,.markdown-body h2{border-bottom:1px solid #eee;padding-bottom:.3em}.markdown-body h2{font-size:1.5em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{color:#777;font-size:.85em}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol.no-list,.markdown-body ul.no-list{list-style-type:none;padding:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-bottom:0;margin-top:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{padding-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{font-size:1em;font-style:italic;font-weight:700;margin-top:16px;padding:0}.markdown-body dl dd{margin-bottom:16px;padding:0 16px}.markdown-body table{display:block;overflow:auto;width:100%;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{border:1px solid #ddd}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{background-color:#fff;box-sizing:initial;max-width:100%}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{background-color:initial;max-width:none;vertical-align:text-top}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{border:1px solid #ddd;display:block;float:left;margin:13px 0 0;overflow:hidden;padding:7px;width:auto}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{clear:both;color:#333;display:block;padding:5px 0 0}.markdown-body span.align-center{clear:both;display:block;overflow:hidden}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{clear:both;display:block;overflow:hidden}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{background-color:#0000000a;border-radius:3px;font-size:85%;margin:0;padding:.2em 0}.markdown-body code:after,.markdown-body code:before,.markdown-body tt:after,.markdown-body tt:before{content:"\00a0";letter-spacing:-.2em}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre{word-wrap:normal}.markdown-body pre>code{background:#0000;border:0;font-size:100%;margin:0;padding:0;white-space:pre;word-break:normal}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{border-radius:3px;font-size:85%;line-height:1.45;overflow:auto}.markdown-body:not(.next-editor) pre{padding:16px}.markdown-body pre code,.markdown-body pre tt{word-wrap:normal;background-color:initial;border:0;display:inline;line-height:inherit;margin:0;max-width:auto;overflow:visible;padding:0}.markdown-body pre code:after,.markdown-body pre code:before,.markdown-body pre tt:after,.markdown-body pre tt:before{content:normal}.markdown-body .csv-data td,.markdown-body .csv-data th{font-size:12px;line-height:1;overflow:hidden;padding:5px;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-line-num{background:#fff;border:0;padding:10px 8px 9px;text-align:right}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{background:#f8f8f8;border-top:0;font-weight:700}.news .alert .markdown-body blockquote{border:0;padding:0 0 0 40px}.activity-tab .news .alert .commits,.activity-tab .news .markdown-body blockquote{padding-left:0}.task-list-item{list-style-type:none}.task-list-item label{font-weight:400}.task-list-item.enabled label{cursor:pointer}.task-list-item+.task-list-item{margin-top:3px}.task-list-item-checkbox{cursor:default!important;float:left;margin:.31em 0 .2em -1.3em!important;vertical-align:middle}.markdown-alert{border-left-style:solid;border-left-width:4px;color:inherit;margin-bottom:16px;padding:8px 16px}.markdown-alert .markdown-alert-title{align-items:center;display:flex;font-weight:500;line-height:1;white-space:break-spaces}.markdown-body .markdown-alert>*{margin-bottom:0;margin-top:16px}.markdown-body .markdown-alert .selection-popover,.markdown-body .markdown-alert>:first-child{margin-top:0}.markdown-alert.markdown-alert-note{border-left-color:var(--hmd-tw-state-info-default)}.markdown-alert.markdown-alert-note .markdown-alert-title{fill:currentColor;color:var(--hmd-tw-state-info-text)}.markdown-alert.markdown-alert-tip{border-left-color:var(--hmd-tw-state-success-default)}.markdown-alert.markdown-alert-tip .markdown-alert-title{fill:currentColor;color:var(--hmd-tw-state-success-text)}.markdown-alert.markdown-alert-important{border-left-color:var(--hmd-tw-border-primary-default)}.markdown-alert.markdown-alert-important .markdown-alert-title{fill:currentColor;color:var(--hmd-tw-text-primary)}.markdown-alert.markdown-alert-warning{border-left-color:var(--hmd-tw-state-warning-default)}.markdown-alert.markdown-alert-warning .markdown-alert-title{fill:currentColor;color:var(--hmd-tw-state-warning-text)}.markdown-alert.markdown-alert-caution{border-left-color:var(--hmd-tw-state-danger-default)}.markdown-alert.markdown-alert-caution .markdown-alert-title{fill:currentColor;color:var(--hmd-tw-state-danger-text)}:root[theme=dark] :not([theme])>*>.markdown-body,:root[theme] [theme=dark] .markdown-body{color:#d4d4d8}:root[theme=dark] :not([theme])>*>.markdown-body h1,:root[theme=dark] :not([theme])>*>.markdown-body h2,:root[theme] [theme=dark] .markdown-body h1,:root[theme] [theme=dark] .markdown-body h2{border-bottom-color:#52525b}:root[theme=dark] :not([theme])>*>.markdown-body h6,:root[theme] [theme=dark] .markdown-body h6{color:#a1a1aa}:root[theme=dark] :not([theme])>*>.markdown-body details,:root[theme] [theme=dark] .markdown-body details{background-color:#303036;color:#d4d4d8}:root[theme=dark] :not([theme])>*>.markdown-body details summary::marker:first-child,:root[theme] [theme=dark] .markdown-body details summary::marker:first-child{color:#d4d4d8}:root[theme=dark] :not([theme])>*>.markdown-body details:hover,:root[theme] [theme=dark] .markdown-body details:hover{background:#303036}:root[theme=dark] :not([theme])>*>.markdown-body details code,:root[theme=dark] :not([theme])>*>.markdown-body details[open]:hover,:root[theme] [theme=dark] .markdown-body details code,:root[theme] [theme=dark] .markdown-body details[open]:hover{background-color:#303036}:root[theme=dark] :not([theme])>*>.markdown-body hr,:root[theme] [theme=dark] .markdown-body hr{background-color:#52525b}:root[theme=dark] :not([theme])>*>.markdown-body blockquote,:root[theme] [theme=dark] .markdown-body blockquote{border-left-color:#71717a;color:#a1a1aa}:root[theme=dark] :not([theme])>*>.markdown-body blockquote a span,:root[theme] [theme=dark] .markdown-body blockquote a span{color:#9894f9}:root[theme=dark] :not([theme])>*>.markdown-body a.mention-anchor.user-card-popover,:root[theme] [theme=dark] .markdown-body a.mention-anchor.user-card-popover{background-color:#453aff26;color:#9894f9}:root[theme=dark] :not([theme])>*>.markdown-body ::selection,:root[theme] [theme=dark] .markdown-body ::selection{background-color:#453aff99}:root[theme=dark] :not([theme])>*>.markdown-body .alert.alert-info,:root[theme] [theme=dark] .markdown-body .alert.alert-info{background-color:#38bdf81a;border-left-color:#0ea5e9;color:#38bdf8}:root[theme=dark] :not([theme])>*>.markdown-body .alert.alert-warning,:root[theme] [theme=dark] .markdown-body .alert.alert-warning{background-color:#fbbf241a;border-left-color:#f59e0b;color:#f59e0b}:root[theme=dark] :not([theme])>*>.markdown-body .alert.alert-success,:root[theme] [theme=dark] .markdown-body .alert.alert-success{background-color:#6db19d26;border-left-color:#55b685;color:#6db19d}:root[theme=dark] :not([theme])>*>.markdown-body .alert.alert-danger,:root[theme] [theme=dark] .markdown-body .alert.alert-danger{background-color:#ef444433;border-left-color:#ef4444;color:#f87171}:root[theme=dark] :not([theme])>*>.markdown-body .mark,:root[theme=dark] :not([theme])>*>.markdown-body mark,:root[theme] [theme=dark] .markdown-body .mark,:root[theme] [theme=dark] .markdown-body mark{background-color:#fbbf241a;color:#f59e0b}:root[theme=dark] :not([theme])>*>.markdown-body .mark span,:root[theme=dark] :not([theme])>*>.markdown-body mark span,:root[theme] [theme=dark] .markdown-body .mark span,:root[theme] [theme=dark] .markdown-body mark span{color:#fbbf24}:root[theme=dark] :not([theme])>*>.markdown-body .highlight pre,:root[theme=dark] :not([theme])>*>.markdown-body pre,:root[theme] [theme=dark] .markdown-body .highlight pre,:root[theme] [theme=dark] .markdown-body pre{background-color:#303036;color:#a1a1aa}:root[theme=dark] :not([theme])>*>.markdown-body .style .token.string,:root[theme=dark] :not([theme])>*>.markdown-body .token.entity,:root[theme=dark] :not([theme])>*>.markdown-body .token.operator,:root[theme=dark] :not([theme])>*>.markdown-body .token.url,:root[theme=dark] :not([theme])>*>.markdown-body.language-css,:root[theme=dark] :not([theme])>*>.markdown-body.token.string,:root[theme] [theme=dark] .markdown-body .style .token.string,:root[theme] [theme=dark] .markdown-body .token.entity,:root[theme] [theme=dark] .markdown-body .token.operator,:root[theme] [theme=dark] .markdown-body .token.url,:root[theme] [theme=dark] .markdown-body.language-css,:root[theme] [theme=dark] .markdown-body.token.string{background:none}:root[theme=dark] :not([theme])>*>.markdown-body :not(pre)>code,:root[theme] [theme=dark] .markdown-body :not(pre)>code{background-color:#3f3f46}:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-tag,:root[theme] [theme=dark] .markdown-body code .hljs-tag{color:#d4d4d8}:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-keyword,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-selector-tag,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-type,:root[theme=dark] :not([theme])>*>.markdown-body code .token.boolean,:root[theme=dark] :not([theme])>*>.markdown-body code .token.constant,:root[theme=dark] :not([theme])>*>.markdown-body code .token.deleted,:root[theme=dark] :not([theme])>*>.markdown-body code .token.number,:root[theme=dark] :not([theme])>*>.markdown-body code .token.property,:root[theme=dark] :not([theme])>*>.markdown-body code .token.symbol,:root[theme=dark] :not([theme])>*>.markdown-body code .token.tag,:root[theme] [theme=dark] .markdown-body code .hljs-keyword,:root[theme] [theme=dark] .markdown-body code .hljs-selector-tag,:root[theme] [theme=dark] .markdown-body code .hljs-type,:root[theme] [theme=dark] .markdown-body code .token.boolean,:root[theme] [theme=dark] .markdown-body code .token.constant,:root[theme] [theme=dark] .markdown-body code .token.deleted,:root[theme] [theme=dark] .markdown-body code .token.number,:root[theme] [theme=dark] .markdown-body code .token.property,:root[theme] [theme=dark] .markdown-body code .token.symbol,:root[theme] [theme=dark] .markdown-body code .token.tag{color:#ff70b4}:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-attribute,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-bullet,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-literal,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-number,:root[theme=dark] :not([theme])>*>.markdown-body code .hljs-symbol,:root[theme=dark] :not([theme])>*>.markdown-body code .token.atrule,:root[theme=dark] :not([theme])>*>.markdown-body code .token.attr-value,:root[theme=dark] :not([theme])>*>.markdown-body code .token.keyword,:root[theme] [theme=dark] .markdown-body code .hljs-attribute,:root[theme] [theme=dark] .markdown-body code .hljs-bullet,:root[theme] [theme=dark] .markdown-body code .hljs-literal,:root[theme] [theme=dark] .markdown-body code .hljs-number,:root[theme] [theme=dark] .markdown-body code .hljs-symbol,:root[theme] [theme=dark] .markdown-body code .token.atrule,:root[theme] [theme=dark] .markdown-body code .token.attr-value,:root[theme] [theme=dark] .markdown-body code .token.keyword{color:#9894f9}:root[theme=dark] :not([theme])>*>.markdown-body pre.plugin-rendered,:root[theme] [theme=dark] .markdown-body pre.plugin-rendered{background-color:#fff;color:#000}:root[theme=dark] :not([theme])>*>.markdown-body table,:root[theme] [theme=dark] .markdown-body table{border-color:#52525b}:root[theme=dark] :not([theme])>*>.markdown-body table thead tr,:root[theme] [theme=dark] .markdown-body table thead tr{background-color:#303036;border-bottom-color:#52525b}:root[theme=dark] :not([theme])>*>.markdown-body table td,:root[theme=dark] :not([theme])>*>.markdown-body table th,:root[theme] [theme=dark] .markdown-body table td,:root[theme] [theme=dark] .markdown-body table th{border-left-color:#52525b;border-top-color:#52525b}:root[theme=dark] :not([theme])>*>.markdown-body table tbody tr,:root[theme=dark] :not([theme])>*>.markdown-body table tr:nth-child(2n),:root[theme] [theme=dark] .markdown-body table tbody tr,:root[theme] [theme=dark] .markdown-body table tr:nth-child(2n){background-color:#27272a}:root[theme=light] :not([theme])>*>.markdown-body,:root[theme] [theme=light] .markdown-body{color:#3f3f46}:root[theme=light] :not([theme])>*>.markdown-body h1,:root[theme=light] :not([theme])>*>.markdown-body h2,:root[theme] [theme=light] .markdown-body h1,:root[theme] [theme=light] .markdown-body h2{border-bottom-color:#e4e4e7}:root[theme=light] :not([theme])>*>.markdown-body h6,:root[theme] [theme=light] .markdown-body h6{color:#71717a}:root[theme=light] :not([theme])>*>.markdown-body iframe,:root[theme] [theme=light] .markdown-body iframe{border:1px solid #e4e4e7;box-sizing:border-box}:root[theme=light] :not([theme])>*>.markdown-body details,:root[theme] [theme=light] .markdown-body details{background-color:#f4f4f5}:root[theme=light] :not([theme])>*>.markdown-body details:hover,:root[theme] [theme=light] .markdown-body details:hover{background:#e4e4e7}:root[theme=light] :not([theme])>*>.markdown-body details[open]:hover,:root[theme] [theme=light] .markdown-body details[open]:hover{background-color:#f4f4f5}:root[theme=light] :not([theme])>*>.markdown-body details code,:root[theme] [theme=light] .markdown-body details code{background-color:#e4e4e7}:root[theme=light] :not([theme])>*>.markdown-body hr,:root[theme] [theme=light] .markdown-body hr{background-color:#d4d4d8}:root[theme=light] :not([theme])>*>.markdown-body blockquote,:root[theme] [theme=light] .markdown-body blockquote{border-left-color:#e4e4e7;color:#71717a}:root[theme=light] :not([theme])>*>.markdown-body blockquote a span,:root[theme] [theme=light] .markdown-body blockquote a span{color:#564dff}:root[theme=light] :not([theme])>*>.markdown-body a.mention-anchor.user-card-popover,:root[theme] [theme=light] .markdown-body a.mention-anchor.user-card-popover{background-color:#ecebfe;color:#564dff}:root[theme=light] :not([theme])>*>.markdown-body ::selection,:root[theme] [theme=light] .markdown-body ::selection{background-color:#cccafc}:root[theme=light] :not([theme])>*>.markdown-body .alert.alert-info,:root[theme] [theme=light] .markdown-body .alert.alert-info{background-color:#e0f2fe;border-left-color:#0284c7;color:#0284c7}:root[theme=light] :not([theme])>*>.markdown-body .alert.alert-warning,:root[theme] [theme=light] .markdown-body .alert.alert-warning{background-color:#fef3c799;border-left-color:#f59e0b;color:#f59e0b}:root[theme=light] :not([theme])>*>.markdown-body .alert.alert-success,:root[theme] [theme=light] .markdown-body .alert.alert-success{background-color:#d9f9e5;border-left-color:#43946c;color:#43946c}:root[theme=light] :not([theme])>*>.markdown-body .alert.alert-danger,:root[theme] [theme=light] .markdown-body .alert.alert-danger{background-color:#fee2e299;border-left-color:#ef4444;color:#ef4444}:root[theme=light] :not([theme])>*>.markdown-body .mark,:root[theme=light] :not([theme])>*>.markdown-body mark,:root[theme] [theme=light] .markdown-body .mark,:root[theme] [theme=light] .markdown-body mark{background-color:#fef3c799;color:#f59e0b}:root[theme=light] :not([theme])>*>.markdown-body .mark span,:root[theme=light] :not([theme])>*>.markdown-body mark span,:root[theme] [theme=light] .markdown-body .mark span,:root[theme] [theme=light] .markdown-body mark span{color:#f59e0b}:root[theme=light] :not([theme])>*>.markdown-body .highlight pre,:root[theme=light] :not([theme])>*>.markdown-body pre,:root[theme] [theme=light] .markdown-body .highlight pre,:root[theme] [theme=light] .markdown-body pre{background-color:#f4f4f5}:root[theme=light] :not([theme])>*>.markdown-body pre.plugin-rendered,:root[theme] [theme=light] .markdown-body pre.plugin-rendered{background-color:inherit;color:inherit}:root[theme=light] :not([theme])>*>.markdown-body :not(pre)>code,:root[theme] [theme=light] .markdown-body :not(pre)>code{background-color:#0000000a}:root[theme=light] :not([theme])>*>.markdown-body table,:root[theme] [theme=light] .markdown-body table{border-color:#e4e4e7}:root[theme=light] :not([theme])>*>.markdown-body table thead tr,:root[theme] [theme=light] .markdown-body table thead tr{background-color:#f4f4f5;border-bottom-color:#d4d4d8}:root[theme=light] :not([theme])>*>.markdown-body table td,:root[theme=light] :not([theme])>*>.markdown-body table th,:root[theme] [theme=light] .markdown-body table td,:root[theme] [theme=light] .markdown-body table th{border-left-color:#e4e4e7;border-top-color:#e4e4e7}:root[theme=light] :not([theme])>*>.markdown-body table tbody tr,:root[theme=light] :not([theme])>*>.markdown-body table tr:nth-child(2n),:root[theme] [theme=light] .markdown-body table tbody tr,:root[theme] [theme=light] .markdown-body table tr:nth-child(2n){background-color:#fdfdfd}.markdown-body{font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;max-width:758px;overflow:visible!important;padding-bottom:40px;padding-top:40px;position:relative}.markdown-body>*{max-width:100%}.markdown-body .alert a,.markdown-body a{color:var(--hmd-tw-link-text-default)}.markdown-body .alert a:focus,.markdown-body .alert a:hover,.markdown-body a:focus,.markdown-body a:hover{color:var(--hmd-tw-link-text-hover)}.markdown-body .alert a:hover,.markdown-body a:hover{text-decoration-thickness:2px;text-underline-offset:4px}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5{font-family:Readex Pro,-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica Neue,Helvetica,Roboto,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;font-weight:700}.markdown-body h1,.markdown-body h2{border-bottom:1px solid}.markdown-body iframe,.markdown-body img{background-color:initial;border-radius:6px;margin:.5rem 0}.markdown-body iframe{max-width:100%;width:728px}.markdown-body details{border-radius:4px;margin-bottom:.5rem;padding:.5rem 1rem}.markdown-body details:hover{transition:all .1s}.markdown-body details summary+p{margin-top:.5rem}.markdown-body details p:last-child{margin-bottom:0}.markdown-body hr{height:2px}.markdown-body img.emoji{border:none;height:20px;vertical-align:middle;width:20px}.markdown-body li small{color:#a1a1aa}.markdown-body blockquote{border-left:3px solid}.markdown-body blockquote .small,.markdown-body blockquote small,.markdown-body li small{display:initial;font-size:85%}.markdown-body a.mention-anchor:before{content:"";margin-right:0}.markdown-body a.mention-anchor.user-card-popover{border-radius:4px;padding:1px 4px}.markdown-body .alert{border:none;border-radius:4px;margin-top:10px}.markdown-body .alert h2,.markdown-body .alert h3,.markdown-body .alert h4,.markdown-body .alert h5,.markdown-body .alert h6{margin-top:0}.markdown-body .alert h2{border:none}.markdown-body .alert.alert-danger,.markdown-body .alert.alert-info,.markdown-body .alert.alert-success,.markdown-body .alert.alert-warning{border-left:3px solid}.markdown-body .highlight pre,.markdown-body .mark,.markdown-body mark,.markdown-body pre{border-radius:4px}.markdown-body pre.abc,.markdown-body pre.flow-chart,.markdown-body pre.fretboard,.markdown-body pre.graphviz,.markdown-body pre.mermaid,.markdown-body pre.sequence-diagram,.markdown-body pre.vega-embed{border-radius:4px;max-width:100%;overflow:auto}.markdown-body .code-block-wrapper{border-radius:4px;outline-color:#0000;outline-style:solid;outline-width:1px;position:relative}.markdown-body .code-block-wrapper .code-toolbar{--tw-translate-y:-100%;--tw-shadow:0 3px 15px 0 #00000026;--tw-shadow-colored:0 3px 15px 0 var(--tw-shadow-color);background-color:var(--hmd-tw-element-bg-default);border-color:var(--hmd-tw-border-default);border-radius:4px;border-style:solid;border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);opacity:0;position:absolute;right:0;top:-1px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);visibility:hidden}.markdown-body .code-block-wrapper:hover{outline-color:var(--hmd-tw-border-primary-default);transition-duration:.15s;transition-property:outline-color;transition-timing-function:cubic-bezier(.4,0,.2,1)}.markdown-body .code-block-wrapper:hover .code-toolbar{opacity:1;visibility:visible}.markdown-body table{border:1px solid;border-radius:4px;width:fit-content}.markdown-body table thead tr{border-bottom:1px solid;border-top:none}.markdown-body table tbody tr,.markdown-body table thead tr th{border-top:none}.markdown-body table tbody tr td:first-child,.markdown-body table thead,.markdown-body table thead th:first-child{border-left:none}.markdown-body table td,.markdown-body table th{border:1px solid;border-bottom:none;border-right:none;padding:6px 13px}.markdown-body.next-editor{overflow-x:hidden!important}.markdown-body pre{border:inherit}.markdown-body code{color:inherit}html[lang^=ja] .markdown-body code code,html[lang^=ja] .markdown-body code kbd,html[lang^=ja] .markdown-body code pre{font-family:Source Code Pro,Consolas,monaco,Meiryo,ＭＳ ゴシック,MS Gothic,monospace}html[lang=zh-tw] .markdown-body code code,html[lang=zh-tw] .markdown-body code kbd,html[lang=zh-tw] .markdown-body code pre{font-family:Source Code Pro,Consolas,monaco,Microsoft JhengHei,微軟正黑,monospace}html[lang=zh-cn] .markdown-body code code,html[lang=zh-cn] .markdown-body code kbd,html[lang=zh-cn] .markdown-body code pre{font-family:Source Code Pro,Consolas,monaco,Microsoft YaHei,微软雅黑,monospace}html .markdown-body code[lang^=ja] code,html .markdown-body code[lang^=ja] kbd,html .markdown-body code[lang^=ja] pre{font-family:Source Code Pro,Consolas,monaco,Meiryo,ＭＳ ゴシック,MS Gothic,monospace}html .markdown-body code[lang=zh-tw] code,html .markdown-body code[lang=zh-tw] kbd,html .markdown-body code[lang=zh-tw] pre{font-family:Source Code Pro,Consolas,monaco,Microsoft JhengHei,微軟正黑,monospace}html .markdown-body code[lang=zh-cn] code,html .markdown-body code[lang=zh-cn] kbd,html .markdown-body code[lang=zh-cn] pre{font-family:Source Code Pro,Consolas,monaco,Microsoft YaHei,微软雅黑,monospace}.markdown-body pre code .wrapper{display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}.markdown-body pre code .gutter{float:left;overflow:hidden;-webkit-user-select:none;user-select:none}.markdown-body pre code .gutter.linenumber{border-right:2px solid #766df8;box-sizing:initial;color:#a1a1aa;cursor:default;display:inline-block;min-width:20px;padding:0 8px 0 0;position:relative;text-align:right;z-index:4}.markdown-body pre code .gutter.linenumber>span:before{content:attr(data-linenumber)}.markdown-body pre code .code{float:left;margin:0 0 0 16px}.markdown-body .gist .line-numbers{border-bottom:none;border-left:none;border-top:none}.markdown-body .gist .line-data{border:none}.markdown-body .gist table{border-collapse:inherit!important;border-spacing:0}.markdown-body code[data-gist-id]{background:none;padding:0}.markdown-body code[data-gist-id]:after,.markdown-body code[data-gist-id]:before{content:""}.markdown-body code[data-gist-id] .blob-num{border:unset}.markdown-body code[data-gist-id] table{margin-bottom:unset;overflow:unset}.markdown-body code[data-gist-id] table tr{background:unset}.markdown-body[dir=rtl] pre{direction:ltr}.markdown-body[dir=rtl] code{direction:ltr;unicode-bidi:embed}.markdown-body .alert{display:flex;flex-direction:column;gap:16px}.markdown-body .alert>*{margin:0}.markdown-body pre.abc,.markdown-body pre.flow-chart,.markdown-body pre.graphviz,.markdown-body pre.mermaid,.markdown-body pre.sequence-diagram,.markdown-body pre.vega{background-color:inherit;border-radius:0;overflow:visible;text-align:center;white-space:inherit}.markdown-body pre.abc>code,.markdown-body pre.flow-chart>code,.markdown-body pre.graphviz>code,.markdown-body pre.mermaid>code,.markdown-body pre.sequence-diagram>code,.markdown-body pre.vega>code{text-align:left}.markdown-body pre.abc>svg,.markdown-body pre.flow-chart>svg,.markdown-body pre.graphviz>svg,.markdown-body pre.mermaid>svg,.markdown-body pre.sequence-diagram>svg,.markdown-body pre.vega>svg{height:100%;max-width:100%}.markdown-body pre>code.wrap{word-wrap:break-word;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap}.markdown-body pre.pseudocode{white-space-collapse:collapse}.markdown-body summary{display:list-item}.markdown-body summary:focus{outline:none}.markdown-body details summary{cursor:pointer}.markdown-body details:not([open])>:not(summary){display:none}.markdown-body figure{margin:1em 40px}.markdown-body .mark,.markdown-body mark{background-color:#fff1a7}:root[theme] .markdown-body{line-height:1.75}:root[theme] .markdown-body ::marker,:root[theme] .markdown-body code{color:var(--hmd-tw-text-default)}:root[theme] .markdown-body h1,:root[theme] .markdown-body h2,:root[theme] .markdown-body h3,:root[theme] .markdown-body h4,:root[theme] .markdown-body h5,:root[theme] .markdown-body h6{overflow:visible}:root[theme] .markdown-body h1 .octicon-link,:root[theme] .markdown-body h2 .octicon-link,:root[theme] .markdown-body h3 .octicon-link,:root[theme] .markdown-body h4 .octicon-link,:root[theme] .markdown-body h5 .octicon-link,:root[theme] .markdown-body h6 .octicon-link{color:var(--hmd-tw-text-subtle)}:root[theme] .markdown-body .anchor{left:0;margin-left:0;position:absolute}:root[theme] .markdown-body .gist table{border-color:inherit}:root[theme] .markdown-body .gist table thead tr{background-color:inherit;border-bottom-color:inherit}:root[theme] .markdown-body .gist table td,:root[theme] .markdown-body .gist table th{border-left-color:inherit;border-top-color:inherit}:root[theme] .markdown-body .gist table tbody tr,:root[theme] .markdown-body .gist table tr:nth-child(2n){background-color:inherit}:root[theme] .markdown-body ol ol,:root[theme] .markdown-body ol ul,:root[theme] .markdown-body ul ol,:root[theme] .markdown-body ul ul{margin-bottom:12px;margin-top:6px}@media (max-width:767px){.markdown-body h1{font-size:1.6em}.markdown-body h2{font-size:1.4em}.markdown-body h3{font-size:1.125em}}.vimeo,.youtube{background-color:#000;background-position:50%;background-repeat:no-repeat;background-size:contain;cursor:pointer;display:table;overflow:hidden;text-align:center}.vimeo,.youtube{position:relative;width:100%}.youtube{padding-bottom:56.25%}.vimeo img{object-fit:contain;width:100%;z-index:0}.youtube img{object-fit:cover;z-index:0}.vimeo iframe,.youtube iframe,.youtube img{height:100%;left:0;position:absolute;top:0;width:100%}.vimeo iframe,.youtube iframe{vertical-align:middle;z-index:1}.vimeo .icon,.youtube .icon{color:#fff;height:auto;left:50%;opacity:.3;position:absolute;top:50%;transform:translate(-50%,-50%);transition:opacity .2s;width:auto;z-index:0}.vimeo:hover .icon,.youtube:hover .icon{opacity:.6;transition:opacity .2s}.slideshare .inner,.speakerdeck .inner{position:relative;width:100%}.slideshare .inner iframe,.speakerdeck .inner iframe{bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.figma{display:table;padding-bottom:56.25%;position:relative;width:100%}.figma iframe{border:1px solid #eee;bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.markmap-container{height:300px}.markmap-container>svg{height:100%;width:100%}.MJX_Assistive_MathML{display:none}#MathJax_Message{z-index:1000!important}.ui-infobar{color:var(--hmd-tw-text-default);font-size:14px;margin:25px auto -25px;max-width:760px;position:relative;z-index:2}.ui-infobar .ui-user-icon.small{height:18px;margin:2px;vertical-align:top;width:18px}.toc .invisable-node{list-style-type:none}.ui-toc{bottom:20px;position:fixed;z-index:998}.ui-toc.both-mode{margin-left:2px}.ui-toc.both-mode .ui-toc-label{border-bottom-left-radius:0;border-top-left-radius:0;height:40px;padding:10px 4px}:root[theme=light] :not([theme])>*>.ui-toc .ui-toc-label,:root[theme] [theme=light] .ui-toc-label{background-color:#fdfdfd;border-color:#d4d4d8;color:#a1a1aa}:root[theme=light] :not([theme])>*>.ui-toc .ui-toc-label:active,:root[theme=light] :not([theme])>*>.ui-toc .ui-toc-label:hover,:root[theme] [theme=light] .ui-toc-label:active,:root[theme] [theme=light] .ui-toc-label:hover{background-color:#f4f4f5;border-color:#d4d4d8;color:#a1a1aa}:root[theme=dark] :not([theme])>*>.ui-toc .ui-toc-label,:root[theme=dark] :not([theme])>*>.ui-toc .ui-toc-label:active,:root[theme=dark] :not([theme])>*>.ui-toc .ui-toc-label:hover,:root[theme] [theme=dark] .ui-toc-label,:root[theme] [theme=dark] .ui-toc-label:active,:root[theme] [theme=dark] .ui-toc-label:hover{background-color:#303036;border-color:#52525b;color:#a1a1aa}:root[theme=dark] :not([theme])>*>.ui-toc.both-mode .ui-toc-label,:root[theme] [theme=dark] .ui-toc.both-mode .ui-toc-label{background-color:#303036;border-color:#3f3f46;color:#d4d4d8}:root[theme=dark] :not([theme])>*>.ui-toc.both-mode .ui-toc-label:hover,:root[theme] [theme=dark] .ui-toc.both-mode .ui-toc-label:hover{background-color:#52525b}.ui-toc-label{border:1px solid;transition:opacity .2s}.ui-toc .open .ui-toc-label,.ui-toc-label:hover{opacity:1;transition:opacity .2s}.ui-toc-dropdown{letter-spacing:normal;margin-bottom:20px;margin-top:20px;max-height:70vh;max-width:45vw;overflow:auto;padding-left:10px;padding-right:10px;text-align:inherit;width:25vw}.ui-toc-dropdown.dropdown-menu{box-shadow:0 3px 15px 0 #00000026}.ui-toc-dropdown>.toc{max-height:calc(70vh - 100px);overflow:auto}.ui-toc-dropdown[dir=rtl] .nav{letter-spacing:.0029em;padding-right:0}.ui-toc-dropdown a{overflow:hidden;text-overflow:ellipsis;white-space:pre}.ui-toc-dropdown .nav>li>a{color:var(--hmd-tw-text-subtle);display:block;font-size:12px;font-weight:500;line-height:16px;padding:4px 20px}.ui-toc-dropdown .nav>li:first-child:last-child>ul,.ui-toc-dropdown .toc.expand ul{display:block}.ui-toc-dropdown .nav>li>a:focus,.ui-toc-dropdown .nav>li>a:hover{background-color:initial;border-color:var(--hmd-tw-border-bold);border-style:solid;border-width:0 0 0 1px;color:#000;color:var(--hmd-tw-text-emphasize);padding-left:19px;text-decoration:none}.ui-toc-dropdown[dir=rtl] .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav>li>a:hover{border-left:none;border-right:1px solid #000;padding-right:19px}.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a{background-color:initial;border-color:var(--hmd-tw-border-bold);border-style:solid;border-width:0 0 0 2px;color:var(--hmd-tw-text-emphasize);font-weight:600;padding-left:18px}.ui-toc-dropdown[dir=rtl] .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav>.active>a{border-width:0 2px 0 medium;border-left:0;border-color:var(--hmd-tw-border-bold);border-style:solid;padding-right:18px}.ui-toc-dropdown .nav .nav{display:none;padding-bottom:10px}.ui-toc-dropdown .nav>.active>ul{display:block}.ui-toc-dropdown .nav .nav>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:30px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a{padding-right:30px}.ui-toc-dropdown .nav .nav>li>ul>li>a{font-size:12px;font-weight:400;padding-bottom:1px;padding-left:40px;padding-top:1px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a{padding-right:40px}.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover{padding-left:29px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:hover{padding-right:29px}.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover{padding-left:39px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:hover{padding-right:39px}.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a{font-weight:500;padding-left:28px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>a{padding-right:28px}.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a{font-weight:500;padding-left:38px}.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active>a{padding-right:38px}.ui-affix-toc{max-height:70vh;max-width:15vw;overflow:auto;position:fixed;top:0}.back-to-top,.expand-toggle,.go-to-bottom{color:var(--hmd-tw-text-subtle);display:block;font-size:12px;font-weight:500;line-height:16px;margin-left:10px;margin-top:10px;padding:2px 10px}.back-to-top:focus,.back-to-top:hover,.expand-toggle:focus,.expand-toggle:hover,.go-to-bottom:focus,.go-to-bottom:hover{color:var(--hmd-tw-text-primary);text-decoration:none}.back-to-top,.go-to-bottom{margin-top:0}.ui-user-icon{background-position:50%;background-repeat:no-repeat;background-size:cover;border-radius:50%;display:block;height:20px;margin-bottom:2px;margin-right:5px;margin-top:2px;width:20px}.ui-user-icon.small{display:inline-block;height:18px;margin:0 0 .2em;vertical-align:middle;width:18px}.ui-infobar>small>span{line-height:22px}.ui-infobar>small .dropdown{display:inline-block}.ui-infobar>small .dropdown a:focus,.ui-infobar>small .dropdown a:hover{text-decoration:none}.ui-more-info{cursor:pointer;vertical-align:middle}.ui-connectedGithub{line-height:23px;white-space:nowrap}.ui-connectedGithub a.file-path{text-decoration:none}.ui-connectedGithub a.file-path:active,.ui-connectedGithub a.file-path:hover{text-decoration:underline}.unselectable{-webkit-user-select:none;-o-user-select:none;user-select:none}.selectable{-webkit-user-select:text;-o-user-select:text;user-select:text}.inline-spoiler-section{cursor:pointer}.inline-spoiler-section .spoiler-text{background-color:#333;border-radius:2px}.inline-spoiler-section .spoiler-text>*{opacity:0}.inline-spoiler-section .spoiler-img{filter:blur(10px)}.inline-spoiler-section.raw{background-color:#333;border-radius:2px}.inline-spoiler-section.raw>*{opacity:0}.inline-spoiler-section.unveil{cursor:auto}.inline-spoiler-section.unveil .spoiler-text{background-color:#3333331a}.inline-spoiler-section.unveil .spoiler-text>*{opacity:1}.inline-spoiler-section.unveil .spoiler-img{filter:none}@media print{blockquote,div,img,pre,table{page-break-inside:avoid!important}a[href]:after{font-size:12px!important}}.markdown-body.slides{color:#222;position:relative;z-index:1}.markdown-body.slides:before{background-color:currentColor;bottom:0;box-shadow:0 0 0 50vw;content:"";display:block;left:0;position:absolute;right:0;top:0;z-index:-1}.markdown-body.slides section[data-markdown]{background-color:#fff;margin-bottom:1.5em;position:relative;text-align:center}.markdown-body.slides section[data-markdown] code{text-align:left}.markdown-body.slides section[data-markdown]:before{content:"";display:block;padding-bottom:56.23%}.markdown-body.slides section[data-markdown]>div:first-child{left:1em;max-height:100%;overflow:hidden;position:absolute;right:1em;top:50%;transform:translateY(-50%)}.markdown-body.slides section[data-markdown]>ul{display:inline-block}.markdown-body.slides>section>section+section:after{border:3px solid #777;content:"";height:1.5em;position:absolute;right:1em;top:-1.5em}.site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,sans-serif}html[lang^=ja] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ ゴシック,sans-serif}html[lang=zh-tw] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] .site-ui-font{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}body{font-smoothing:subpixel-antialiased!important;-webkit-font-smoothing:subpixel-antialiased!important;-moz-osx-font-smoothing:auto!important;-webkit-overflow-scrolling:touch;font-family:Source Sans Pro,Helvetica,Arial,sans-serif;letter-spacing:.025em}html[lang^=ja] body{font-family:Source Sans Pro,Helvetica,Arial,Hiragino Kaku Gothic Pro,ヒラギノ角ゴ Pro W3,Osaka,Meiryo,メイリオ,MS Gothic,ＭＳ ゴシック,sans-serif}html[lang=zh-tw] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang TC,Microsoft JhengHei,微軟正黑,sans-serif}html[lang=zh-cn] body{font-family:Source Sans Pro,Helvetica,Arial,PingFang SC,Microsoft YaHei,微软雅黑,sans-serif}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}abbr[data-original-title],abbr[title]{cursor:help}body.modal-open{overflow-y:auto;padding-right:0!important}svg{text-shadow:none}
    </style>
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js" integrity="sha256-3Jy/GbSLrg0o9y5Z5n1uw0qxZECH7C6OQpVBgNFYa0g=" crossorigin="anonymous"></script>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js" integrity="sha256-g6iAfvZp+nDQ2TdTR/VVKJf3bGro4ub5fvWSWVRi2NE=" crossorigin="anonymous"></script>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.min.js" integrity="sha256-8E4Is26QH0bD52WoQpcB+R/tcWQtpzlCojrybUd7Mxo=" crossorigin="anonymous"></script>
    <![endif]-->
</head>

<body>
    <div id="doc" class="markdown-body container-fluid comment-enabled" data-hard-breaks="true"><h1 id="Atomic-floating-point-minmax" data-id="Atomic-floating-point-minmax"><a class="anchor hidden-xs" href="#Atomic-floating-point-minmax" title="Atomic-floating-point-minmax"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Atomic floating-point min/max</span></h1><p><strong><span>Document number</span></strong><span>: P3008R4.</span><br>
<strong><span>Date</span></strong><span>: 2025-02-20.</span><br>
<strong><span>Authors</span></strong><span>: Gonzalo Brito Gadeschi, David Sankel &lt;</span><a href="mailto:dsankel@adobe.com" target="_blank" rel="noopener"><span>dsankel@adobe.com</span></a><span>&gt;.</span><br>
<strong><span>Reply to</span></strong><span>: gonzalob </span><em><span>at</span></em><span> </span><a href="http://nvidia.com" target="_blank" rel="noopener"><span>nvidia.com</span></a><span> .</span><br>
<strong><span>Audience</span></strong><span>: LWG.</span></p><style data-custom-style="">
ins {
    color:green;
    text-decoration:underline;
}
del {
    color:red;
    background-color:yellow;
    text-decoration:line-through;
}
bdi {
    color:black;
    background-color:lightblue;
    text-decoration:underline;
}
.markdown-body {
    max-width: 900px;
    text-align: justify;
}
</style><p><big><span>Table of Contents</span></big></p><p><span class="toc"><ul>
<li><a href="#Atomic-floating-point-minmax" title="Atomic floating-point min/max">Atomic floating-point min/max</a></li>
<li><a href="#Changelog" title="Changelog">Changelog</a></li>
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Survey-of-programming-language-floating-point-minmax-API-semantics" title="Survey of programming language floating-point min/max API semantics">Survey of programming language floating-point min/max API semantics</a><ul>
<li><a href="#C-stdminstdmax" title="C++ std::min/std::max">C++ std::min/std::max</a></li>
<li><a href="#C-fminfmax" title="C fmin/fmax">C fmin/fmax</a></li>
<li><a href="#C23-minimummaximumminimumNumbermaximumNumber" title="C23 minimum/maximum/minimumNumber/maximumNumber">C23 minimum/maximum/minimumNumber/maximumNumber</a></li>
</ul>
</li>
<li><a href="#Impact-of-replacing-min-with-fminimum_num" title="Impact of replacing min with fminimum_num">Impact of replacing min with fminimum_num</a></li>
<li><a href="#Survey-of-hardware-atomic-floating-point-minmax-API-semantics" title="Survey of hardware atomic floating-point min/max API semantics">Survey of hardware atomic floating-point min/max API semantics</a><ul>
<li><a href="#Performance-impact-of-atomicltfloating-pointgtfetch_min_max-semantics" title="Performance impact of atomic<floating-point>::fetch_min/_max semantics">Performance impact of atomic&lt;floating-point&gt;::fetch_min/_max semantics</a></li>
</ul>
</li>
<li><a href="#Design-space" title="Design space">Design space</a></li>
<li><a href="#Wording" title="Wording">Wording</a></li>
<li><a href="#References" title="References">References</a></li>
</ul>
</span></p><h1 id="Changelog" data-id="Changelog"><a class="anchor hidden-xs" href="#Changelog" title="Changelog"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Changelog</span></h1><ul>
<li>
<p><strong><span>Revision 4</span></strong><span>:</span></p>
<ul>
<li><span>Fix typos.</span></li>
<li><span>Merge Remarks clause.</span></li>
<li><span>Incorporate </span><code>constexpr</code><span> updates from </span><a href="http://wg21.link/p3309" target="_blank" rel="noopener"><span>P3309</span></a><span>.</span></li>
<li><span>Add option to add few new </span><code>&lt;cmath&gt;</code><span> functions as part of this paper.</span></li>
</ul>
</li>
<li>
<p><strong><span>Revision 3</span></strong><span>: LWG changes.</span></p>
<ul>
<li>
<p><span>LWG polled this paper in Wroclaw: Put 3008r3 into C++26 (pending checking by BSA and TK) and following adoption of P3348</span></p>
<table>
<thead>
<tr>
<th><span>F</span></th>
<th><span>A</span></th>
<th><span>N</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>8</span></td>
<td><span>0</span></td>
<td><span>0</span></td>
</tr>
</tbody>
</table>
</li>
</ul>
</li>
<li>
<p><strong><span>Revision 2</span></strong><span> (post SG6 review): SG6 took the following poll and the paper is updated accordingly:</span></p>
<ul>
<li>
<p><span>Poll 1: Accept SG1 proposal as listed in P3008R1 with "implementation-defined" instead of "unspecified" and forward to LEWG.</span></p>
<table>
<thead>
<tr>
<th><span>SF</span></th>
<th><span>F</span></th>
<th><span>N</span></th>
<th><span>A</span></th>
<th><span>SA</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>2</span></td>
<td><span>3</span></td>
<td><span>2</span></td>
<td><span>2</span></td>
<td><span>0</span></td>
</tr>
</tbody>
</table>
<p><span>Consensus.</span></p>
<ul>
<li><span>A: preference for no fetch_min/max default, but rather explicit fetch_fminimum/minimum_num</span></li>
<li><span>A: implementation-define may cause pessimistic implementations.</span></li>
<li><span>SF: two authors.</span></li>
</ul>
</li>
<li>
<p><span>Poll 2: If one of the input is a NaN then it is "unspecified" whether the result value is either a NaN or the other value.</span></p>
<table>
<thead>
<tr>
<th><span>SF</span></th>
<th><span>F</span></th>
<th><span>N</span></th>
<th><span>A</span></th>
<th><span>SA</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>2</span></td>
<td><span>2</span></td>
<td><span>3</span></td>
<td><span>0</span></td>
<td><span>1</span></td>
</tr>
</tbody>
</table>
<p><span>Consensus.</span><br>
<span>SA: bad for teachability.</span></p>
</li>
<li>
<p><span>Poll 3: With respect to signaling NaNs, SG6 recommends:</span></p>
<ul>
<li><span>for </span><code>fetch_fminimum</code><span>/</span><code>fminimum_num</code><span>/</span><code>fmaximum</code><span>/</span><code>fmaximum_num</code><span> to be specified in terms of their corresponding C23 APIs (ignore signaling NaNs in the wording, refer to C23), and</span></li>
<li><span>for fetch_min/max, to not explicitly specify signaling NaN behavior (ignore signaling NaNs in the wording)</span></li>
</ul>
<table>
<thead>
<tr>
<th><span>SF</span></th>
<th><span>F</span></th>
<th><span>N</span></th>
<th><span>A</span></th>
<th><span>SA</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>4</span></td>
<td><span>3</span></td>
<td><span>2</span></td>
<td><span>0</span></td>
<td><span>0</span></td>
</tr>
</tbody>
</table>
<p><span>Consensus.</span></p>
</li>
</ul>
</li>
<li>
<p><strong><span>Revision 1</span></strong><span> (post SG1 review):</span></p>
<ul>
<li><span>Update to account for removal of min/max from P0493.</span></li>
<li><span>Update C17 to C23 wording for signaling NaNs.</span></li>
<li><span>SG1 DIRECTION POLL:</span>
<ol style="padding-left: 2em;">
<li>
<p><span>The default fetch_min(T, mo=SC)-&gt;T, fetch_max(T, mo=SC)-&gt;T should exist</span></p>
</li>
<li>
<p><span>The default fetch_min, fetch_max should have these semantics:</span><br>
<span>* Which value is stored in the atomic is unspecified if an input is a NaN</span><br>
<span>* Implementations should treat -0 as less than +0 (use normative encouragement)</span><br>
<span>* (Note: must </span><em><span>not</span></em><span> require std::min/max)</span></p>
</li>
<li>
<p><span>Users need a way to specify semantics (up to LEWG how to achieve this):</span><br>
<span>* Must-have: fminimum/fmaximum</span><br>
<span>* Must-have: fminimum_num/fmaximum_num</span><br>
<span>* Can have if LEWG desires it but we do not: std::min/max</span></p>
<table>
<thead>
<tr>
<th><span>SF</span></th>
<th><span>F</span></th>
<th><span>N</span></th>
<th><span>A</span></th>
<th><span>SA</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>5</span></td>
<td><span>6</span></td>
<td><span>2</span></td>
<td><span>0</span></td>
<td><span>0</span></td>
</tr>
</tbody>
</table>
<p><span>Unanimous consent</span></p>
</li>
</ol>
</li>
</ul>
</li>
<li>
<p><strong><span>Revision 0</span></strong><span>: initial revision.</span></p>
</li>
</ul><h1 id="Introduction" data-id="Introduction"><a class="anchor hidden-xs" href="#Introduction" title="Introduction"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Introduction</span></h1><p><a href="https://wg21.link/P0493R4" target="_blank" rel="noopener"><span>P0493R4</span></a><span> </span><em><span>Atomic minimum/maximum</span></em><span> proposes the addition of </span><code>atomic&lt;T&gt;::fetch_min</code><span> and </span><code>atomic&lt;T&gt;::fetch_max</code><span> operations, which atomically perform </span><code>std::min</code><span> and </span><code>std::max</code><span> computations.</span></p><p><span>The Varna '23 plenary rejected these semantics for </span><code>atomic&lt;floating-point&gt;</code><span> types due to safety concerns. These semantics deviate from the current standard practice, as defined by </span><a href="https://ieeexplore.ieee.org/document/8766229" target="_blank" rel="noopener"><span>IEEE 754-2019</span></a><span> recommendations and the capabilities of available hardware.</span></p><p><span>These operations were removed from subsequent revisions of </span><a href="https://wg21.link/P0493" target="_blank" rel="noopener"><span>P0493</span></a><span>. This paper proposes adding these operations to C++ with different semantics. It reviews the semantics proposed in </span><a href="https://wg21.link/P0493R4" target="_blank" rel="noopener"><span>P0493R4</span></a><span> and standard practice: </span><a href="https://iremi.univ-reunion.fr/IMG/pdf/ieee-754-2008.pdf" target="_blank" rel="noopener"><span>IEEE 754-2008</span></a><span>, </span><a href="https://ieeexplore.ieee.org/document/8766229" target="_blank" rel="noopener"><span>IEEE 754-2019</span></a><span>, and available hardware support. It then explores the design space and evaluates alternative solutions.</span></p><p><span>Finally, the authors propose two coherent alternatives and concrete wording changes implementing some of the semantics </span><a href="https://ieeexplore.ieee.org/document/8766229" target="_blank" rel="noopener"><span>IEEE 754-2019</span></a><span> recommends all vendors implement.</span></p><h1 id="Survey-of-programming-language-floating-point-minmax-API-semantics" data-id="Survey-of-programming-language-floating-point-minmax-API-semantics"><a class="anchor hidden-xs" href="#Survey-of-programming-language-floating-point-minmax-API-semantics" title="Survey-of-programming-language-floating-point-minmax-API-semantics"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Survey of programming language floating-point min/max API semantics</span></h1><p><span>This section provides an overview of widely used floating-point </span><code>min</code><span>/</span><code>max</code><span> semantics. We will focus on how various </span><code>min</code><span>/</span><code>max</code><span> semantics handle the following "corner cases":</span></p><ul>
<li><strong><span>Signed zero</span></strong><span>: Should </span><code>-0</code><span> be considered less than </span><code>+0</code><span> (</span><code>-0 &lt; +0</code><span>), or should </span><code>-0</code><span> and </span><code>+0</code><span> be treated as equivalent (</span><code>-0 == +0</code><span>) such that, e.g., </span><code>min(+0, -0) = +0</code><span>?</span></li>
<li><strong><span>One quiet NaN</span></strong><span> (qNaN): when one of the arguments is a qNaN, should it be treated as </span><em><span>Missing Data</span></em><span> and the other argument returned, or should it be treated as an </span><em><span>Error</span></em><span> and propagated?</span>
<ul>
<li><strong><span>Missing Data</span></strong><span>: returns the other argument: </span><code>min(x, qNaN) = x</code><span> and </span><code>min(qNaN, x) = x</code><span>.</span></li>
<li><strong><span>Error</span></strong><span>: propagates the qNaN:</span><code>min(x, qNaN) = qNaN</code><span> and </span><code>min(qNaN, x) = qNaN</code><span>.</span></li>
</ul>
</li>
</ul><p><span>Explicitly and intentionally, this paper ignores:</span></p><ul>
<li><strong><span>Signaling NaNs</span></strong><span>: C23 specifies that their full support is not required, and where their specification is not provided leaving them as implementation-defined behavior (either as quiet NaN or signaling NaN). C++ does not specify anything about them beyond what C23 covers. An analysis of signaling NaNs and their impact on this proposal is left to a future version of this paper and captured as a current unresolved question in a latter section of this proposal.</span></li>
<li><strong><span>NaN payload propagation</span></strong><span>: IEEE 754 does not mandate it, and programming languages do not interpret NaN payloads.</span></li>
</ul><p><strong><span>Table 1</span></strong><span> summarizes the semantics of the different C or C++ APIs regarding Signed Zeros and Quiet NaN handling and documents whether implementations that implement particular IEEE 754 semantics are valid implementations of the APIs.</span></p><table>
<thead>
<tr>
<th><span>C API</span></th>
<th><span>C++ API</span></th>
<th><span>Signed Zeros</span></th>
<th><span>One qNaN</span></th>
<th><span>IEEE 754 impl valid?</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>-</span></td>
<td><code>min</code><br><code>max</code></td>
<td><span>Equivalent</span></td>
<td><span>Undefined</span><br><span>[1]</span></td>
<td><span>Ternary [0]</span></td>
</tr>
<tr>
<td><code>fmin</code><br><code>fmax</code></td>
<td><span>-</span></td>
<td><span>Equivalent</span><br><span>or</span><br><code>-0 &lt; +0</code><span> (QoI) [2]</span></td>
<td><span>Missing Data</span></td>
<td><code>minNum</code><br><code>maxNum</code><br><span>or (QoI)</span><br><code>minimumNumber</code><br><code>maximumNumber</code></td>
</tr>
<tr>
<td><code>fminimum</code><br><code>fmaximum</code></td>
<td><span>-</span></td>
<td><code>-0 &lt; +0</code></td>
<td><span>Error</span></td>
<td><code>minimum</code><br><code>maximum</code></td>
</tr>
<tr>
<td><code>fminimum_num</code><br><code>fmaximum_num</code></td>
<td><span>-</span></td>
<td><code>-0 &lt; +0</code></td>
<td><span>Missing Data</span></td>
<td><code>minimumNumber</code><br><code>maximumNumber</code></td>
</tr>
</tbody>
</table><p><span>[0] Ternary semantics: </span><code>min(x,y) = y &lt; x? y : x</code><span>, </span><code>max(x,y) = x &lt; y? y : x</code><span>; both return the first argument if the arguments are equivalent or one argument is a NaN.</span><br>
<span>[1] In practice, the same implementation as for valid values is used, and the first argument passed to the function is returned (the second argument of the ternary expression is picked, since the conditional involving a NaN is always false).</span><br>
<span>[2] QoI: "Quality of Implementation", i.e., </span><code>fmin</code><span> does not require </span><code>-0 &lt; +0</code><span>, but it recommends that high quality implementations implement it.</span></p><h2 id="C-stdminstdmax" data-id="C-stdminstdmax"><a class="anchor hidden-xs" href="#C-stdminstdmax" title="C-stdminstdmax"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>C++ </span><code>std::min</code><span>/</span><code>std::max</code></h2><p><span>The </span><code>std::min</code><span> and </span><code>std::max</code><span> algorithms have a </span><em><span>precondition</span></em><span> on their arguments (</span><a href="http://eel.is/c++draft/alg.min.max#1" target="_blank" rel="noopener"><span>[alg.min.max.1]</span></a><span>):</span></p><blockquote>
<p><span>Preconditions: For the first form, </span><code>T</code><span> meets the </span><a href="http://eel.is/c++draft/utility.arg.requirements#tab:cpp17.lessthancomparable" target="_blank" rel="noopener"><span>Cpp17LessThanComparable</span></a><span> requirements (Table </span><a href="http://eel.is/c++draft/utility.arg.requirements#tab:cpp17.lessthancomparable" target="_blank" rel="noopener"><span>Cpp17LessThanComparable</span></a><span>).</span></p>
</blockquote><p><span>which NaNs do not satisfy.</span></p><details><summary>Rationale.</summary>
<br>
<p><span>Per </span><a href="https://wg21.link/structure.requirements#4" target="_blank" rel="noopener"><span>[structure.requirements#4]</span></a><span> and </span><a href="https://wg21.link/structure.requirements#8" target="_blank" rel="noopener"><span>[structure.requirements#8]</span></a><span>, which uses floating points as an example, the syntactic requirements apply to the type, but the semantic requirements only apply to the values actually passed to the algorithm.</span></p>
<p><span>The </span><a href="http://eel.is/c++draft/utility.arg.requirements#tab:cpp17.lessthancomparable" target="_blank" rel="noopener"><span>Cpp17LessThanComparable</span></a><span> concept, which requires:</span></p>
<blockquote>
<p><code>&lt;</code><span> is a strict weak ordering relation (</span><a href="http://eel.is/c++draft/alg.sorting#general-4" target="_blank" rel="noopener"><span>[alg.sorting]</span></a><span>)</span></p>
</blockquote>
<p><span>Which is specified in </span><a href="http://eel.is/c++draft/alg.sorting#general-4" target="_blank" rel="noopener"><span>[alg.sorting#general-4]</span></a><span>:</span></p>
<blockquote>
<p><span>The term strict refers to the requirement of an irreflexive relation (</span><code>!comp(x, x)</code><span> for all </span><code>x</code><span>), and the term weak to requirements that are not as strong as those for a total ordering, but stronger than those for a partial ordering. If we define </span><code>equiv(a, b)</code><span> as </span><code>!comp(a, b) &amp;&amp; !comp(b, a)</code><span>, then the requirements are that </span><code>comp</code><span> and </span><code>equiv</code><span> both be transitive relations:</span></p>
<ol style="padding-left: 2em;">
<li><code>comp(a, b) &amp;&amp; comp(b, c)</code><span> implies </span><code>comp(a, c)</code></li>
<li><code>equiv(a, b)</code><span> &amp;&amp; </span><code>equiv(b, c)</code><span> implies </span><code>equiv(a, c)</code></li>
</ol>
<p><span>[Note 1: Under these conditions, it can be shown that</span><br>
<span>3. </span><code>equiv</code><span> is an equivalence relation,</span><br>
<span>4. </span><code>comp</code><span> induces a well-defined relation on the equivalence classes determined by </span><code>equiv</code><span>, and</span><br>
<span>5. the induced relation is a strict total ordering.</span><br>
<span>— end note]</span></p>
</blockquote>
<p><span>and is satisfied by all floating-point values with the exception of NaNs.</span></p>
</details><br><p><span>For valid values, implementations follow (</span><a href="http://eel.is/c++draft/alg.min.max" target="_blank" rel="noopener"><span>[alg.min.max]</span></a><span>):</span></p><blockquote>
<p><span>[</span><code>std::min</code><span>]:</span><br>
<em><span>Returns</span></em><span>: The smaller value. Returns the first argument when the arguments are equivalent.</span></p>
</blockquote><blockquote>
<p><span>[</span><code>std::max</code><span>]:</span><br>
<em><span>Returns</span></em><span>: The larger value. Returns the first argument when the arguments are equivalent.</span></p>
</blockquote><p><span>which preserves equivalence between </span><code>-0</code><span> and </span><code>+0</code><span> (</span><a href="https://cpp.godbolt.org/z/84j4Kse46" target="_blank" rel="noopener"><span>godbolt</span></a><span>):</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token comment">// Listing 1: std::min/std::max</span>
<span class="token keyword">auto</span> min <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">auto</span><span class="token operator">&amp;</span> a<span class="token punctuation">,</span> <span class="token keyword">auto</span><span class="token operator">&amp;</span> b<span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token keyword">auto</span><span class="token operator">&amp;</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> std<span class="token double-colon punctuation">::</span><span class="token function">min</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// y &lt; x ? y : x;</span>
<span class="token keyword">auto</span> max <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">auto</span><span class="token operator">&amp;</span> a<span class="token punctuation">,</span> <span class="token keyword">auto</span><span class="token operator">&amp;</span> b<span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token keyword">auto</span><span class="token operator">&amp;</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> std<span class="token double-colon punctuation">::</span><span class="token function">max</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// x &lt; y ? y : x;</span>

<span class="token function">min</span><span class="token punctuation">(</span>qNaN<span class="token punctuation">,</span> <span class="token number">2.f</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// UB: qNaN</span>
<span class="token function">max</span><span class="token punctuation">(</span>qNaN<span class="token punctuation">,</span> <span class="token number">2.f</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// UB: qNaN</span>
<span class="token function">min</span><span class="token punctuation">(</span><span class="token number">2.f</span><span class="token punctuation">,</span> qNaN<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// UB: 2</span>
<span class="token function">max</span><span class="token punctuation">(</span><span class="token number">2.f</span><span class="token punctuation">,</span> qNaN<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// UB: 2</span>
<span class="token function">min</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// -0</span>
<span class="token function">max</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// -0</span>
<span class="token function">min</span><span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// +0</span>
<span class="token function">max</span><span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// +0</span>
</div></div></code></pre>
      </div><p><span>In all standard library implementations surveyed, the manifestation of the </span><em><span>undefined behavior</span></em><span> is to return the first argument; this is depicted in the example with "UB: qNaN" and "UB: 2".</span></p><p><span>The behavior of these semantics are:</span></p><ul>
<li><strong><span>Signed Zero</span></strong><span>: undefined since not totally ordered.</span></li>
<li><strong><span>One qNaN</span></strong><span>: undefined since not totally ordered.</span></li>
</ul><p><span>In concurrent programs, these semantics become even less intuitive, e.g., the sign of the result of a concurrent computation may depend on the order in which an observer sitting on top of the memory location observes the operations from different threads. If negative and positive zero are equivalent, the sign of this final result may differ across executions.</span></p><h2 id="C-fminfmax" data-id="C-fminfmax"><a class="anchor hidden-xs" href="#C-fminfmax" title="C-fminfmax"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>C </span><code>fmin</code><span>/</span><code>fmax</code></h2><p><span>The semantics of the </span><a href="https://open-std.org/JTC1/SC22/WG14/www/docs/n3096.pdf" target="_blank" rel="noopener"><span>ISO/IEC 9899:2024 (C23) standard</span></a><span> </span><code>fmin</code><span>/</span><code>fmax</code><span> functions are compatible with implementations of </span><a href="https://iremi.univ-reunion.fr/IMG/pdf/ieee-754-2008.pdf" target="_blank" rel="noopener"><span>IEEE 754-2008</span></a><span> </span><code>minNum</code><span> and </span><code>maxNum</code><span> and of </span><a href="https://ieeexplore.ieee.org/document/8766229" target="_blank" rel="noopener"><span>IEEE 754-2019</span></a><span> </span><code>minimumNumber</code><span>/</span><code>maximumNumber</code><span>. The </span><code>fmin</code><span>/</span><code>fmax</code><span> functions are available in C++ through the </span><code>&lt;cmath&gt;</code><span> header as </span><code>std::fmin/std::fmax</code><span>.</span></p><p><span>The semantics of C's </span><code>fmin</code><span>/</span><code>fmax</code></p><ul>
<li><strong><span>Signed zero</span></strong><span>:</span>
<ul>
<li><code>-0</code><span> may be equivalent to </span><code>+0</code><span> (</span><code>minNum</code><span>/</span><code>maxNum</code><span>)</span></li>
<li><code>-0 &lt; +0</code><span> allowed as QoI (</span><code>minimumNumber</code><span>/</span><code>maximumNumber</code><span> guarantee it).</span></li>
</ul>
</li>
<li><strong><span>One qNaN</span></strong><span>: missing data (other value returned).</span></li>
</ul><details><summary>(collapsible) C23 fmin/fmax specification.</summary>
<blockquote>
<p><span>[From C23 7.12.12 Maximum, minimum, and positive difference functions]</span></p>
<p><span>[fmax 7.12.12.2]: The </span><code>fmax</code><span> functions determine the maximum numeric value of their arguments. [Note 299]</span></p>
<p><span>[fmin 7.12.12.3]: The </span><code>fmin</code><span> functions determine the minimum numeric value of their arguments. [Note 300]</span></p>
<p><span>[Note 299]: Quiet NaN arguments are treated as missing data: if one argument is a quiet NaN and the other numeric, then the fmax functions choose the numeric value. See F.10.9.2.</span></p>
<p><span>[Note 300]: The </span><code>fmin</code><span> functions are analogous to the </span><code>fmax</code><span> functions in their treatment of quiet NaNs.</span></p>
<p><span>[Note 461]: Ideally, </span><code>fmax</code><span> would be sensitive to the sign of zero, for example </span><code>fmax(−0.0, +0.0)</code><span> would return </span><code>+0</code><span>; however, implementation in software might be impractical.</span></p>
<p><strong><span>NOTE 1</span></strong><span>: The </span><code>fmax</code><span> and </span><code>fmin</code><span> functions are similar to the fmaximum_num and fminimum_num functions, though may differ in which signed zero is returned when the arguments are differently signed zeros and in their treatment of signaling NaNs (see F.10.9.5).</span></p>
<p><span>[F.10.9.2 The fmax functions]: If just one argument is a NaN, the fmax functions return the other argument (if both arguments are NaNs, the functions return a NaN).</span></p>
<p><span>[F.10.9.3 The fmin functions]: The fmin functions are analogous to the fmax functions (see F.10.9.2).</span></p>
<p><span>[F.2.1]: This annex does not require the full support for signaling NaNs specified in IEC 60559. This annex uses the term NaN, unless explicitly qualified, to denote quiet NaNs. Where specification of signaling NaNs is not provided, the behavior of signaling NaNs is implementation-defined (either treated as an IEC 60559 quiet NaN or treated as an IEC 60559 signaling NaN). 442) [</span><span class="smartypants">…</span><span>] To support signaling NaNs as specified in IEC 60559, an implementation should adhere to the following recommended practice.</span></p>
<p><strong><span>Recommended practice</span></strong></p>
<p><span>Any floating-point operator or </span><code>&lt;math.h&gt;</code><span> function or macro with a signaling NaN input, unless explicitly specified otherwise, raises an "invalid" floating-point exception.</span></p>
<p><span>[F.10.9.5] The </span><code>fmaximum_num</code><span>, </span><code>fminimum_num</code><span>, </span><code>fmaximum_mag_num</code><span>, and </span><code>fminimum_mag_num</code><span> functions</span><br>
<span>These functions return the number if one argument is a number and the other is a quiet or signaling NaN. If both arguments are NaNs, a quiet NaN is returned. If an argument is a signaling NaN, the "invalid" floating-point exception is raised (even though the function returns the number when the other argument is a number).</span></p>
</blockquote>
</details><details><summary>(collapsible) [IEEE 754-2008] minNum/maxNum specification.</summary>
<blockquote>
<p><span>[5.3.1  General operations]</span><br>
<code>sourceFormat minNum(source, source)</code><br>
<code>sourceFormat maxNum(source, source)</code></p>
<p><code>minNum(x, y)</code><span> is the canonicalized number </span><code>x</code><span> if </span><code>x&lt;y</code><span>, </span><code>y</code><span> if </span><code>y&lt;x</code><span>, the canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it is either </span><code>x</code><span> or </span><code>y</code><span>, canonicalized (this means results might differ among implementations).</span></p>
<p><code>maxNum(x, y)</code><span> is the canonicalized number </span><code>y</code><span> if </span><code>x&lt;y</code><span>, </span><code>x</code><span> if </span><code>y&lt;x</code><span>, the canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it is either </span><code>x</code><span> or </span><code>y</code><span>, canonicalized (this means results might differ among implementations).</span></p>
</blockquote>
</details><br><p><span>That is, in the presence of a qNaN, these return the value, but signed zeros may or may not be equivalent:</span></p><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token comment">// Listing 2: fmin/fmax</span>
<span class="token function">fmin</span><span class="token punctuation">(</span>qNaN<span class="token punctuation">,</span> <span class="token number">2.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token number">2</span>
<span class="token function">fmax</span><span class="token punctuation">(</span>qNaN<span class="token punctuation">,</span> <span class="token number">2.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token number">2</span>
<span class="token function">fmin</span><span class="token punctuation">(</span><span class="token number">2.f</span><span class="token punctuation">,</span> qNaN<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token number">2</span>
<span class="token function">fmax</span><span class="token punctuation">(</span><span class="token number">2.f</span><span class="token punctuation">,</span> qNaN<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token number">2</span>
<span class="token function">fmin</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">0</span> <span class="token operator">or</span> <span class="token operator">+</span><span class="token number">0</span>
<span class="token function">fmax</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">0</span> <span class="token operator">or</span> <span class="token operator">+</span><span class="token number">0</span>
<span class="token function">fmin</span><span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">0</span> <span class="token operator">or</span> <span class="token operator">+</span><span class="token number">0</span>
<span class="token function">fmax</span><span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">0</span> <span class="token operator">or</span> <span class="token operator">+</span><span class="token number">0</span>
</div></div></code></pre>
      </div><p><a href="https://ieeexplore.ieee.org/document/8766229" target="_blank" rel="noopener"><span>IEEE 754-2019</span></a><span> removed </span><code>minNum</code><span> and</span><code>maxNum</code><span> operations and replaced them with </span><code>minimumNumber</code><span>/</span><code>maximumNumber</code><span> and </span><code>minimum</code><span>/</span><code>maximum</code><span>. These are surveyed in the next section. The gist of the rationale for their removal from </span><a href="https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf" target="_blank" rel="noopener"><span>The Removal/Demotion of </span><code>MinNum</code><span> and </span><code>MaxNum</code><span> Operations from IEEE 754-2018</span></a><span> is:</span></p><blockquote>
<p><span>These [minNum, maxNum] operations are removed from or demoted in IEEE std 754-2018, due to their non-associativity. [</span><span class="smartypants">…</span><span>] With this non-associativity, different compilations or runs on parallel processing can return different answers [</span><span class="smartypants">…</span><span>].</span></p>
</blockquote><h2 id="C23-minimummaximumminimumNumbermaximumNumber" data-id="C23-minimummaximumminimumNumbermaximumNumber"><a class="anchor hidden-xs" href="#C23-minimummaximumminimumNumbermaximumNumber" title="C23-minimummaximumminimumNumbermaximumNumber"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>C23 </span><code>minimum</code><span>/</span><code>maximum</code><span>/</span><code>minimumNumber</code><span>/</span><code>maximumNumber</code></h2><p><a href="https://ieeexplore.ieee.org/document/8766229" target="_blank" rel="noopener"><span>IEEE 754-2019</span></a><span> removed </span><code>minNum</code><span>/</span><code>maxNum</code><span> and recommends programming languages to provide their replacements instead: </span><code>minimumNumber</code><span>/</span><code>maximumNumber</code><span>/</span><code>minimum</code><span>/</span><code>maximum</code><span>.</span></p><details><summary>(collapsible) IEEE 754-2019 minimum/maximum/minimumNumber/maximumNumber specification.</summary>
<blockquote>
<p><span>[9.6 Minimum and maximum operations]: Language standards should define the following homogeneous general-computational operations for all</span><br>
<span>supported arithmetic formats:</span></p>

      <div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code>sourceFormat minimum(source, source)
sourceFormat minimumNumber(source, source)
sourceFormat maximum(source, source)
sourceFormat maximumNumber(source, source)
</code></pre>
      </div>
      
<p><code>minimum(x, y)</code><span> is </span><code>x</code><span> if </span><code>x &lt; y</code><span>, </span><code>y</code><span> if </span><code>y &lt; x</code><span>, and a quiet NaN if either operand is a NaN, according to 6.2. For this operation, </span><code>−0</code><span> compares less than </span><code>+0</code><span>. Otherwise (i.e., when </span><code>x=y</code><span> and signs are the same) it is either </span><code>x</code><span> or </span><code>y</code><span>.</span></p>
<p><code>minimumNumber(x, y)</code><span> is </span><code>x</code><span> if </span><code>x&lt;y</code><span>, </span><code>y</code><span> if </span><code>y&lt;x</code><span>, and the number if one operand is a number and the other is a NaN. For this operation, </span><code>−0</code><span> compares less than </span><code>+0</code><span>. If </span><code>x = y</code><span> and signs are the same it is either </span><code>x</code><span> or </span><code>y</code><span>. If both operands are NaNs, a quiet NaN is returned, according to 6.2.</span></p>
<p><code>maximum(x, y)</code><span> is </span><code>x</code><span> if </span><code>x &gt; y</code><span>, </span><code>y</code><span> if </span><code>y &gt; x</code><span>, and a quiet NaN if either operand is a NaN, according to 6.2. For this operation, +0 compares greater than </span><code>−0</code><span>. Otherwise (i.e., when </span><code>x=y</code><span> and signs are the same) it is either </span><code>x</code><span> or </span><code>y</code><span>.</span></p>
<p><code>maximumNumber(x, y)</code><span> is </span><code>x</code><span> if </span><code>x&gt;y</code><span>, </span><code>y</code><span> if </span><code>y&gt;x</code><span>, and the number if one operand is a number and the other is a NaN. For this operation, </span><code>+0</code><span> compares greater than </span><code>−0</code><span>. If </span><code>x = y</code><span> and signs are the same it is either </span><code>x</code><span> or </span><code>y</code><span>. If both operands are NaNs, a quiet NaN is returned, according to 6.2.</span></p>
<p><span>[6.2 Operations with NaNs]: For an operation with quiet NaN inputs, except as stated otherwise, if a floating-point result is to be delivered the result shall be a canonical quiet NaN.</span></p>
</blockquote>
</details><details><summary>(collapsible) C23 fmaximum/fminimum/fmaximum_num/fminimum_num specification.</summary>
<blockquote>
<p><span>[From C23 7.12.12 Maximum, minimum, and positive difference functions]</span></p>
<p><span>[fmaximum - 7.12.12.4]: The </span><code>fmaximum</code><span> functions return the maximum value of their arguments.</span></p>
<p><span>The </span><code>fmaximum</code><span> functions determine the maximum value of their arguments. For these functions, </span><code>+0</code><span> is considered greater than </span><code>−0</code><span>. These functions differ from the </span><code>fmaximum_num</code><span> functions only in their treatment of NaN arguments (see F.10.9.4, F.10.9.5).</span></p>
<p><span>[fminimum - 7.12.12.5]: The </span><code>fminimum</code><span> functions return the minimum value of their arguments.</span></p>
<p><span>The </span><code>fminimum</code><span> functions determine the minimum value of their arguments. For these functions, </span><code>−0</code><span> is considered less than </span><code>+0</code><span>. These functions differ from the fminimum_num functions only in their treatment of NaN arguments (see F.10.9.4, F.10.9.5).</span></p>
<p><span>[fmaximum_num - 7.12.12.8]: The </span><code>fmaximum_num</code><span> functions return the maximum value of their numeric arguments.</span></p>
<p><span>The </span><code>fmaximum_num</code><span> functions determine the maximum value of their numeric arguments. They determine the number if one argument is a number and the other is a NaN. These functions differ from the </span><code>fmaximum</code><span> functions only in their treatment of NaN arguments (see F.10.9.4, F.10.9.5).</span></p>
<p><span>[fminimum_num - 7.12.12.9]: The </span><code>fminimum_num</code><span> functions return the minimum value of their numeric arguments.</span></p>
<p><span>The </span><code>fminimum_num</code><span> functions determine the minimum value of their numeric arguments. They determine the number if one argument is a number and the other is a NaN. These functions differ from the fminimum functions only in their treatment of NaN arguments (see F.10.9.4, F.10.9.5).</span></p>
<p><span>[F.10.9.4]: These functions treat NaNs like other functions in &lt;math.h&gt; (see F.10).</span></p>
<p><span>[F.10 Mathematics &lt;math.h&gt; and &lt;tgmath.h&gt;]: Functions with a NaN argument return a NaN result and raise no floating-point exception, except</span><br>
<span>where explicitly stated otherwise.</span></p>
</blockquote>
</details><br><p><span>The semantics of these functions matches for signed zero: </span><code>-0 &lt; +0</code><span>, and differs in their treatment when one argument is a qNaN:</span></p><ul>
<li><strong><span>Missing Data</span></strong><span>: </span><code>fminimumNumber</code><span>/</span><code>fmaximumNumber</code><span>, return the Number.</span></li>
<li><strong><span>Errors</span></strong><span>: </span><code>fminimum</code><span>/</span><code>fmaximum</code><span>, propagate the qNaN.</span></li>
</ul><div class="code-block-wrapper"><div class="code-toolbar"><button class="rounded text-normal font-normal leading-normal flex bg-transparent text-text-default border border-solid border-transparent hocus:bg-element-bg-hover hocus:text-text-emphasize hover:border-element-bg-hover focus:shadow-[0_0_0_2px_#77777733] focus:border-element-border-hover disabled:bg-transparent disabled:hocus:bg-transparent disabled:hocus:border-transparent disabled:text-element-text-disabled disabled:hocus:text-element-text-disabled ui-code-block-copy-button p-[7px]" data-state="closed"><i class="inline-flex ph ph-clipboard-text" aria-hidden="true" style="width: 20px; height: 20px; font-size: 20px; line-height: 20px;"></i></button></div>
        <pre><code class="cpp hljs"><div class="wrapper"><div class="gutter linenumber"><span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span></div><div class="code"><span class="token comment">// Listing 3: fminimum/fmaximum</span>
<span class="token function">fminimum</span><span class="token punctuation">(</span>qNaN<span class="token punctuation">,</span> <span class="token number">2.f</span><span class="token punctuation">)</span><span class="token operator">:</span> qNaN
<span class="token function">fmaximum</span><span class="token punctuation">(</span>qNaN<span class="token punctuation">,</span> <span class="token number">2.f</span><span class="token punctuation">)</span><span class="token operator">:</span> qNaN
<span class="token function">fminimum</span><span class="token punctuation">(</span><span class="token number">2.f</span><span class="token punctuation">,</span> qNaN<span class="token punctuation">)</span><span class="token operator">:</span> qNaN
<span class="token function">fmaximum</span><span class="token punctuation">(</span><span class="token number">2.f</span><span class="token punctuation">,</span> qNaN<span class="token punctuation">)</span><span class="token operator">:</span> qNaN
<span class="token function">fminimum</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">0</span>
<span class="token function">fmaximum</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">+</span><span class="token number">0</span>
<span class="token function">fminimum</span><span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">0</span>
<span class="token function">fmaximum</span><span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">+</span><span class="token number">0</span>
    
<span class="token function">fminimum_num</span><span class="token punctuation">(</span>qNaN<span class="token punctuation">,</span> <span class="token number">2.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token number">2</span>
<span class="token function">fmaximum_num</span><span class="token punctuation">(</span>qNaN<span class="token punctuation">,</span> <span class="token number">2.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token number">2</span>
<span class="token function">fminimum_num</span><span class="token punctuation">(</span><span class="token number">2.f</span><span class="token punctuation">,</span> qNaN<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token number">2</span>
<span class="token function">fmaximum_num</span><span class="token punctuation">(</span><span class="token number">2.f</span><span class="token punctuation">,</span> qNaN<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token number">2</span>
<span class="token function">fminimum_num</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">0</span>
<span class="token function">fmaximum_num</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">+</span><span class="token number">0</span>
<span class="token function">fminimum_num</span><span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">0</span>
<span class="token function">fmaximum_num</span><span class="token punctuation">(</span><span class="token operator">+</span><span class="token number">0.f</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">0.f</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token operator">+</span><span class="token number">0</span>
</div></div></code></pre>
      </div><h1 id="Impact-of-replacing-min-with-fminimum_num" data-id="Impact-of-replacing-min-with-fminimum_num"><a class="anchor hidden-xs" href="#Impact-of-replacing-min-with-fminimum_num" title="Impact-of-replacing-min-with-fminimum_num"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Impact of replacing </span><code>min</code><span> with </span><code>fminimum_num</code></h1><p><strong><span>Table 2</span></strong><span> captures the impact of replacing </span><code>min</code><span> with </span><code>fminimum_num</code><span> is as follows:</span></p><table>
<thead>
<tr>
<th><code>std::min</code><span>/</span><code>std::max</code></th>
<th><code>fminimum_num</code><span>/</span><code>fmaximum_num</code></th>
</tr>
</thead>
<tbody>
<tr>
<td><code>min(qNaN, 2.f); // UB: qNaN</code><br><code>max(qNaN, 2.f); // UB: qNaN</code><br><code>min(+0.f, -0.f); // +0</code><br><code>max(-0.f, +0.f); // -0</code></td>
<td><code>fminimum_num(qNaN, 2.f); // 2</code><br><code>fmaximum_num(qNaN, 2.f); // 2</code><br><code>fminimum_num(+0.f, -0.f); // -0</code><br><code>fmaximum_num(-0.f, +0.f); // +0</code></td>
</tr>
</tbody>
</table><p><span>That is, when the first input of </span><code>std::min</code><span>/</span><code>std::max</code><span> is a qNaN, then these switch from exhibiting </span><em><span>undefined behavior</span></em><span> to returning a number, and when signed zeros are involved, there is a case where the result has a different sign.</span></p><h1 id="Survey-of-hardware-atomic-floating-point-minmax-API-semantics" data-id="Survey-of-hardware-atomic-floating-point-minmax-API-semantics"><a class="anchor hidden-xs" href="#Survey-of-hardware-atomic-floating-point-minmax-API-semantics" title="Survey-of-hardware-atomic-floating-point-minmax-API-semantics"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Survey of hardware atomic floating-point min/max API semantics</span></h1><p><span>On systems without native support for atomic floating-point min/max operations, these operations must be performed atomically, e.g., using a CAS loop, a compare-and-conditional-store loop, an LL/SC loop, or, e.g., by taking a lock, which would make the atomic not lock-free. In these systems, the memory latency overhead may outweight the cost of performing the actual </span><em><span>arithmetic</span></em><span> portion of the min/max operations, and extra effort may be required to ensure forward progress properties like starvation freedom, and therefore those systems are not considered here.</span></p><p><strong><span>Table 3</span></strong><span> surveys the publicly known Instruction Set Architectures (ISAs) with atomic floating-point min/max operations, which are all GPU ISAs:</span></p><table>
<thead>
<tr>
<th><span>Vendor</span></th>
<th><span>ISA</span></th>
<th><span>Instructions</span></th>
<th><span>IEEE-2019 compat</span></th>
<th><span>Signed Zero</span></th>
<th><span>Quiet NaN</span></th>
</tr>
</thead>
<tbody>
<tr>
<td><span>AMD</span></td>
<td><a href="https://www.amd.com/content/dam/amd/en/documents/instinct-tech-docs/instruction-set-architectures/instinct-mi200-cdna2-instruction-set-architecture.pdf" target="_blank" rel="noopener"><span>CDNA2</span></a><span>+</span></td>
<td><a href="https://www.amd.com/content/dam/amd/en/documents/instinct-tech-docs/instruction-set-architectures/instinct-mi200-cdna2-instruction-set-architecture.pdf" target="_blank" rel="noopener"><span>MIN</span></a><br><a href="https://www.amd.com/content/dam/amd/en/documents/instinct-tech-docs/instruction-set-architectures/instinct-mi200-cdna2-instruction-set-architecture.pdf" target="_blank" rel="noopener"><span>MAX</span></a></td>
<td><code>minimumNumber</code><br><code>maximumNumber</code></td>
<td><span>-0 &lt; +0</span></td>
<td><span>Missing Data</span></td>
</tr>
<tr>
<td><span>Intel</span></td>
<td><a href="https://www.intel.com/content/www/us/en/docs/graphics-for-linux/developer-reference/1-0/alchemist-arctic-sound-m.html" target="_blank" rel="noopener"><span>Xe ISA</span></a></td>
<td><code>AOP_FMIN</code><br><code>AOP_FMAX</code><span> [0]</span></td>
<td><code>minimumNumber</code><br><code>maximumNumber</code></td>
<td><span>-0 &lt; +0</span></td>
<td><span>Missing Data</span></td>
</tr>
<tr>
<td><span>NVIDIA</span></td>
<td><a href="https://docs.nvidia.com/cuda/parallel-thread-execution/index.html" target="_blank" rel="noopener"><span>PTX</span></a></td>
<td><a href="https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#parallel-synchronization-and-communication-instructions-atom" target="_blank" rel="noopener"><span>atom</span></a><br><a href="https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#parallel-synchronization-and-communication-instructions-red" target="_blank" rel="noopener"><span>red</span></a></td>
<td><code>minimumNumber</code><br><code>maximumNumber</code></td>
<td><span>-0 &lt; +0</span></td>
<td><span>Missing Data</span></td>
</tr>
<tr>
<td><span>Neutral [1]</span></td>
<td><a href="http://htmlpreview.github.io/?https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/EXT/SPV_EXT_shader_atomic_float_min_max.html" target="_blank" rel="noopener"><span>SPIR-V</span></a><span> Extension</span></td>
<td><a href="https://registry.khronos.org/SPIR-V/specs/unified1/OpenCL.ExtendedInstructionSet.100.html" target="_blank" rel="noopener"><span>OpAtomicFMinEXT</span></a><br><a href="https://registry.khronos.org/SPIR-V/specs/unified1/OpenCL.ExtendedInstructionSet.100.html" target="_blank" rel="noopener"><span>OpAtomicFMaxEXT</span></a></td>
<td><span>C </span><code>fmin</code><span>/</span><code>fmax</code></td>
<td><span>Equivalent;</span><br><span>QoI: -0 &lt; +0</span></td>
<td><span>Missing Data</span></td>
</tr>
</tbody>
</table><ul>
<li><span>[0]: Volume 2d: Command Reference: Structures, page 229.</span></li>
<li><span>[1]: The Vulkan extension corresponding to this SPIR-V extension is </span><code>VK_EXT_shader_atomic_float2</code><span>. Hardware that implements it is listed </span><a href="https://vulkan.gpuinfo.org/listdevicescoverage.php?extensionname=VK_EXT_shader_atomic_float2&amp;extensionfeature=shaderBufferFloat32AtomicMinMax&amp;platform=all" target="_blank" rel="noopener"><span>here</span></a><span> and </span><a href="https://vulkan.gpuinfo.org/listdevicescoverage.php?extensionname=VK_EXT_shader_atomic_float2&amp;extensionfeature=shaderSharedFloat32AtomicMinMax&amp;platform=all" target="_blank" rel="noopener"><span>here</span></a><span>.</span></li>
</ul><p><span>All the architectures surveyed order </span><code>-0 &lt; +0</code><span>, treat qNaNs as missing data, and implement IEEE 754-2019 </span><code>minimumNumber</code><span> and </span><code>maximumNumber</code><span> semantics. The SPIR-V extension requires C </span><code>fmin</code><span>/</span><code>fmax</code><span> semantics, which allows </span><code>-0 &lt; +0</code><span> but does not require it.</span></p><p><span>The semantics vendor implement are compatible with C23's </span><code>fminimum_num</code><span>/</span><code>fmaximum_num</code><span>, and C's </span><code>fmin</code><span>/</span><code>fmax</code><span>, but not with C++'s </span><code>std::min</code><span>/</span><code>std::max</code><span> due to the different outcomes when signed-zeros are involved.</span></p><h2 id="Performance-impact-of-atomicltfloating-pointgtfetch_min_max-semantics" data-id="Performance-impact-of-atomicltfloating-pointgtfetch_min_max-semantics"><a class="anchor hidden-xs" href="#Performance-impact-of-atomicltfloating-pointgtfetch_min_max-semantics" title="Performance-impact-of-atomicltfloating-pointgtfetch_min_max-semantics"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Performance impact of </span><code>atomic&lt;floating-point&gt;::fetch_min</code><span>/</span><code>_max</code><span> semantics</span></h2><p><span>We compare the performance impact of two different </span><code>atomic&lt;floating-point&gt;::fetch_max</code><span> semantics:</span></p><ul>
<li><code>std::min</code><span>, which lowers to a CAS-loop that performs </span><code>std::min</code><span> (similar for compare-and-conditional-store), and</span></li>
<li><code>fminimum_num</code><span>, which lowers to native atomic operations,</span></li>
</ul><p><span>using a synthetic micro-benchmark that measures throughput in Giga Operations per Second (y-axis; logarithmic) as a function of the number of threads (x-axis; logarithmic) from 32 to 130'000 hardware threads on an </span><span class="ui-comment-inline-span">NVIDIA GPU system</span><span>.</span></p><img src="https://hackmd.io/_uploads/H1qPahSWp.png" class="center offline-handled error-handled" width="400"><p><span>Modern concurrent systems provide dozens of millions of hardware threads operating on the same shared memory.</span></p><p><span>While native in-memory atomic operations increase throughput until its theoretical peak with just a few thousand threads, the performance of compare and swap strategies decreases as the number of threads increases due to excess contention. At just a few thousand threads, the performance is already four orders of magnitude worse (~10'000x) than that of native in-memory operations. This is why vendors of highly concurrent systems provide these operations.</span></p><p><span>While most CPU ISAs lack native hardware instructions for atomic floating-point min/max, their performance impact is expected to be similar to that of atomic integer min/max. Section 9 of </span><a href="https://wg21.link/P0493R4" target="_blank" rel="noopener"><span>P0493R4</span></a><span> presents benchmarks comparing the performance of a CAS-based implementation against an Arm v8.1 implementation using the native atomic </span><code>ldsmaxl</code><span> instruction. The benchmark covers a range of cores, from 2 to 64. The performance improvement of the native instruction ranges between 2.75x (2 cores) to 1.7x at 64 cores. We expect this behavior to transfer to atomic floating-point min/max.</span></p><p><span>We, unfortunately, do not have benchmarks for other hardware configurations at this time.</span></p><h1 id="Design-space" data-id="Design-space"><a class="anchor hidden-xs" href="#Design-space" title="Design-space"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Design space</span></h1><p><span>SG1 (Concurrency) and SG6 (Numerics) agreed on the following semantics (see polls in the Changelog of Revision's 1 and 2 of this paper):</span></p><ol style="padding-left: 2em;">
<li><span>The "default" </span><code>fetch_min(T, mo=SC)-&gt;T</code><span> and </span><code>fetch_max(T, mo=SC)-&gt;T</code><span> APIs should exist and have these semantics:</span>
<ul>
<li><span>Which value is stored in the atomic is </span><em><span>unspecified</span></em><span> if an input is a NaN.</span></li>
<li><span>Implementations </span><em><span>should</span></em><span> treat </span><code>-0</code><span> as less than </span><code>+0</code><span> (normative encouragement; must </span><em><span>not</span></em><span> require std::min/max).</span></li>
<li><span>No explicit specification of signaling NaN behavior.</span></li>
</ul>
</li>
<li><span>Users need a way to specify </span><code>fminimum</code><span>/</span><code>fmaximum</code><span> and </span><code>fminimum_num</code><span>/</span><code>fmaximum_num</code><span> semantics. These APIs should be specified in term of the corresponding C23 APIs.</span></li>
<li><span>Can have APIs with </span><code>std::min</code><span>/</span><code>std::max</code><span> semantics that leave the handling of signed zero and NaNs as undefined, but SG1 and SG6 do not want these APIs.</span></li>
</ol><p><span>These semantics are different from </span><code>std::min</code><span>/</span><code>std::max</code><span> semantics, which leave the handling of signed-zero and NaNs as undefined behavior, due to these values not being totally ordered. There is precendent in the C++ standard for the atomic operations semantics to deviate from the non-atomic semantics. For example, </span><code>atomic&lt;int&gt;::fetch_add</code><span> wraps around on overflow, instead of exhibiting undefined behavior, see </span><a href="http://eel.is/c++draft/atomics#ref.int-6" target="_blank" rel="noopener"><span>[atomics#ref.int-6]</span></a><span>:</span></p><blockquote>
<p><em><span>Remarks</span></em><span>: For signed integer types, the result is as if the object value and parameters were converted to their corresponding unsigned types, the computation performed on those types, and the result converted back to the signed type.</span></p>
<p><span>[Note 2: There are no undefined results arising from the computation. — end note]</span></p>
</blockquote><p><span>The wording section proposes the actual API.</span></p><h1 id="Wording" data-id="Wording"><a class="anchor hidden-xs" href="#Wording" title="Wording"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>Wording</span></h1><p><span>Add the following to </span><a href="https://eel.is/c++draft/atomics.ref.float" target="_blank" rel="noopener"><span>[atomics.ref.float]</span></a><span> immediately below </span><code>fetch_sub</code><span>:</span></p><pre><code>namespace std {
template &lt;&gt; struct atomic_ref&lt;floating-point&gt; {
  <ins>constexpr floating-point fetch_max(floating-point, memory_order = memory_order::seq_cst) const noexcept;</ins>
  <ins>constexpr floating-point fetch_min(floating-point, memory_order = memory_order::seq_cst) const noexcept;</ins>
  <ins>constexpr floating-point fetch_fmaximum(floating-point, memory_order = memory_order::seq_cst) const noexcept;</ins>
  <ins>constexpr floating-point fetch_fminimum(floating-point, memory_order = memory_order::seq_cst) const noexcept;</ins>
  <ins>constexpr floating-point fetch_fmaximum_num(floating-point, memory_order = memory_order::seq_cst) const noexcept;</ins>
  <ins>constexpr floating-point fetch_fminimum_num(floating-point, memory_order = memory_order::seq_cst) const noexcept;</ins>
};
}</code></pre><pre><code>constexpr floating-point-type fetch_key(floating-point-type operand,
                          memory_order order = memory_order::seq_cst) const noexcept;
</code></pre><ul>
<li><span>Effects: Atomically replaces the value referenced by </span><code>*ptr</code><span> with the result of the computation applied to the value referenced by </span><code>*ptr</code><span> and the given operand. Memory is affected according to the value of order. These operations are atomic read-modify-write operations ([intro.races]).</span></li>
<li><span>Returns: Atomically, the value referenced by *ptr immediately before the effects.</span></li>
<li><span>Remarks: If the result is not a representable value for its type ([expr.pre]), the result is unspecified, but the operations otherwise have no undefined behavior. Atomic arithmetic operations on floating-point-type should conform to the </span><code>std::numeric_limits&lt;floating-point-type&gt;</code><span> traits associated with the floating-point type ([limits.syn]). The floating-point environment ([cfenv]) for atomic arithmetic operations on floating-point-type may be different than the calling thread's floating-point environment.</span></li>
<li><ins><span>Remarks: </span></ins>
<ul>
<li><ins><span>For </span><code>fetch_fmaximum</code><span> and </span><code>fetch_fminimum</code><span>, the maximum and minimum computation is performed as if by </span><code>std::fmaximum</code><span> and </span><code>std::fminimum</code><span>, with the object value and the first parameter as the arguments.</span></ins></li>
<li><ins><span>For </span><code>fetch_fmaximum_num</code><span> and </span><code>fetch_fminimum_num</code><span>, the maximum and minimum computation is performed as if by </span><code>std::fmaximum_num</code><span> and </span><code>std::fminimum_num</code><span>, with the object value and the first parameter as the arguments.</span></ins></li>
<li><ins><span>For </span><code>fetch_max</code><span> and </span><code>fetch_min</code><span>, the maximum and minimum computation is performed as if by </span><code>std::fmaximum_num</code><span> and </span><code>std::fminimum_num</code><span>, with the object value and the first parameter as the arguments. If the given operand or the value referenced by </span><code>*ptr</code><span> are NaN, which of these values is stored at </span><code>*ptr</code><span> is unspecified. If the given operand and the value referenced by </span><code>*ptr</code><span> are differently signed zeros, which of these values is stored at </span><code>*ptr</code><span> is unspecified.</span></ins></li>
</ul>
</li>
<li><ins><span>Recommended practice: The implementation of </span><code>fetch_max</code><span> and </span><code>fetch_min</code><span> should treat negative zero as smaller than positive zero.</span></ins></li>
</ul><p><span>Add the following to </span><a href="https://eel.is/c++draft/atomics.types.float" target="_blank" rel="noopener"><span>[atomics.types.float]</span></a><span> immediately below </span><code>fetch_sub</code><span>:</span></p><pre><code>namespace std {
template &lt;&gt; struct atomic&lt;floating-point&gt; {
  <ins>floating-point fetch_max(floating-point, memory_order = memory_order::seq_cst) volatile noexcept;</ins>
  <ins>constexpr floating-point fetch_max(floating-point, memory_order = memory_order::seq_cst) noexcept;</ins>
  <ins>floating-point fetch_min(floating-point, memory_order = memory_order::seq_cst) volatile noexcept;</ins>
  <ins>constexpr floating-point fetch_min(floating-point, memory_order = memory_order::seq_cst) noexcept;</ins> 
  <ins>floating-point fetch_fmaximum(floating-point, memory_order = memory_order::seq_cst) volatile noexcept;</ins>
  <ins>constexpr floating-point fetch_fmaximum(floating-point, memory_order = memory_order::seq_cst) noexcept;</ins>
  <ins>floating-point fetch_fminimum(floating-point, memory_order = memory_order::seq_cst) volatile noexcept;</ins>
  <ins>constexpr floating-point fetch_fminimum(floating-point, memory_order = memory_order::seq_cst) noexcept;</ins>
  <ins>floating-point fetch_fmaximum_num(floating-point, memory_order = memory_order::seq_cst) volatile noexcept;</ins>
  <ins>constexpr floating-point fetch_fmaximum_num(floating-point, memory_order = memory_order::seq_cst) noexcept;</ins>
  <ins>floating-point fetch_fminimum_num(floating-point, memory_order = memory_order::seq_cst) volatile noexcept;</ins>
  <ins>constexpr floating-point fetch_fminimum_num(floating-point, memory_order = memory_order::seq_cst) noexcept;</ins>  
};
}</code></pre><p><code></code></p><pre><code><span>T fetch_key(T operand, memory_order order = memory_order::seq_cst) volatile noexcept;</span><br>
<span>constexpr T fetch_key(T operand, memory_order order = memory_order::seq_cst) noexcept;</span></code></pre><p></p><ul>
<li><span>Constraints: For the volatile overload of this function, is_always_lock_free is true.</span></li>
<li><span>Effects: Atomically replaces the value pointed to by this with the result of the computation applied to the value pointed to by this and the given operand. Memory is affected according to the value of order. These operations are atomic read-modify-write operations ([intro.multithread]).</span></li>
<li><span>Returns: Atomically, the value pointed to by this immediately before the effects.</span></li>
<li><span>Remarks: If the result is not a representable value for its type ([expr.pre]) the result is unspecified, but the operations otherwise have no undefined behavior. Atomic arithmetic operations on floating-point-type should conform to the std​::​numeric_limits</span>&lt;floating-point-type&gt;<span> traits associated with the floating-point type ([limits.syn]). The floating-point environment ([cfenv]) for atomic arithmetic operations on floating-point-type may be different than the calling thread's floating-point environment.</span></li>
<li><ins><span>Remarks</span></ins><span>:</span>
<ul>
<li><ins><span>For </span><code>fetch_fmaximum</code><span> and </span><code>fetch_fminimum</code><span>, the maximum and minimum computation is performed as if by </span><code>std::fmaximum</code><span> and </span><code>std::fminimum</code><span>, with the object value and the first parameter as the arguments.</span></ins></li>
<li><ins><span>For </span><code>fetch_fmaximum_num</code><span> and </span><code>fetch_fminimum_num</code><span>, the maximum and minimum computation is performed as if by </span><code>std::fmaximum_num</code><span> and </span><code>std::fminimum_num</code><span>, with the object value and the first parameter as the arguments.</span></ins></li>
<li><ins><span>For </span><code>fetch_max</code><span> and </span><code>fetch_min</code><span>, the maximum and minimum computation is performed as if by </span><code>std::fmaximum_num</code><span> and </span><code>std::fminimum_num</code><span>, with the object value and the first parameter as the arguments. If the given operand or the object value are NaN, which of these values replaces the object value is unspecified. If the given operand and the object value are differently signed zeros, which of these values replaces the object value is unspecified.</span></ins></li>
</ul>
</li>
<li><ins><span>Recommended practice: The implementation of </span><code>fetch_max</code><span> and </span><code>fetch_min</code><span> should treat negative zero as smaller than positive zero.</span></ins></li>
</ul><p><span>Update </span><code>__cpp_lib_atomic_min_max</code><span> version macro in </span><a href="https://eel.is/c++draft/version.syn#2" target="_blank" rel="noopener"><code>&lt;version&gt;</code><span> synopsis [version.syn]</span></a><span> to the C++ version this feature is introduced in:</span></p><pre><code>#define __cpp_lib_atomic_min_max <del>202403L</del><ins>______</ins>L // freestanding, also in &lt;atomic&gt;
</code></pre><p><strong><span>EDITORIAL NOTES</span></strong><span>:</span></p><p><span>This paper relies on:</span></p><ul>
<li><span>The C23 math functions, which have not been merged into C++26 draft yet (see </span><a href="https://wg21.link/p3348" target="_blank" rel="noopener"><span>P3348</span></a><span>).</span></li>
<li><span>New </span><code>constexpr </code>&lt;cmath&gt;<span>` functions.</span></li>
</ul><p><span>If </span><a href="https://wg21.link/p3348" target="_blank" rel="noopener"><span>P3348</span></a><span> is merged into the draft, then the </span><code>&lt;cmath&gt;</code><span> extensions this paper requires on are the following.</span></p><p><span>Add the following to </span><a href="https://eel.is/c++draft/cmath.syn" target="_blank" rel="noopener"><span>[math.syn]</span></a><span> after </span><code>fmin</code><span> and </span><code>fmax</code><span>:</span></p><pre><code>namespace std {

// ...

  constexpr floating-point-type fmax(floating-point-type x, floating-point-type y);
  constexpr float               fmaxf(float x, float y);
  constexpr long double         fmaxl(long double x, long double y);

  constexpr floating-point-type fmin(floating-point-type x, floating-point-type y);
  constexpr float               fminf(float x, float y);
  constexpr long double         fminl(long double x, long double y);


  <ins>constexpr floating-point-type fmaximum(floating-point-type x, floating-point-type y);</ins>
  
  <ins>constexpr floating-point-type fmaximum_num(floating-point-type x, floating-point-type y);</ins>
   
  <ins>constexpr floating-point-type fminimum(floating-point-type x, floating-point-type y);</ins>
  
  <ins>constexpr floating-point-type fminimum_num(floating-point-type x, floating-point-type y);</ins>

} // namespace std</code></pre><h1 id="References" data-id="References"><a class="anchor hidden-xs" href="#References" title="References"><span class="octicon octicon-link ph ph-link-simple-horizontal"></span></a><span>References</span></h1><ol style="padding-left: 2em;">
<li><a href="https://wg21.link/P0493R4" target="_blank" rel="noopener"><span>P0493R4 Atomic maximum/minimum</span></a><span>.</span></li>
<li><a href="https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/background/minNum_maxNum_Removal_Demotion_v3.pdf" target="_blank" rel="noopener"><span>The Removal/Demotion of MinNum and MaxNum Operations from IEEE 754™-2018</span></a><span>.</span></li>
<li><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2273.pdf" target="_blank" rel="noopener"><span>Min-max functions</span></a><span> Proposal for TS 18661 update WG14 N2273.</span></li>
<li><a href="https://open-std.org/JTC1/SC22/WG14/www/docs/n3096.pdf" target="_blank" rel="noopener"><span>ISO/IEC 9899:2024 C23 standard</span></a><span>.</span></li>
<li><a href="https://iremi.univ-reunion.fr/IMG/pdf/ieee-754-2008.pdf" target="_blank" rel="noopener"><span>ANSI/IEEE Std 754-2008</span></a><span>.</span></li>
<li><a href="https://ieeexplore.ieee.org/document/8766229" target="_blank" rel="noopener"><span>ANSI/IEEE Std 754-2019</span></a><span>.</span></li>
</ol></div>
    <div class="ui-toc dropup unselectable hidden-print" style="display:none;">
        <div class="pull-right dropdown">
            <a id="tocLabel" class="ui-toc-label btn btn-default" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" title="Table of content">
                <i class="fa fa-bars"></i>
            </a>
            <ul id="ui-toc" class="ui-toc-dropdown dropdown-menu" aria-labelledby="tocLabel">
                <div class="toc"><ul class="nav">
<li><a href="#Atomic-floating-point-minmax" title="Atomic floating-point min/max">Atomic floating-point min/max</a></li>
<li><a href="#Changelog" title="Changelog">Changelog</a></li>
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Survey-of-programming-language-floating-point-minmax-API-semantics" title="Survey of programming language floating-point min/max API semantics">Survey of programming language floating-point min/max API semantics</a><ul class="nav">
<li><a href="#C-stdminstdmax" title="C++ std::min/std::max">C++ std::min/std::max</a></li>
<li><a href="#C-fminfmax" title="C fmin/fmax">C fmin/fmax</a></li>
<li><a href="#C23-minimummaximumminimumNumbermaximumNumber" title="C23 minimum/maximum/minimumNumber/maximumNumber">C23 minimum/maximum/minimumNumber/maximumNumber</a></li>
</ul>
</li>
<li><a href="#Impact-of-replacing-min-with-fminimum_num" title="Impact of replacing min with fminimum_num">Impact of replacing min with fminimum_num</a></li>
<li><a href="#Survey-of-hardware-atomic-floating-point-minmax-API-semantics" title="Survey of hardware atomic floating-point min/max API semantics">Survey of hardware atomic floating-point min/max API semantics</a><ul class="nav">
<li><a href="#Performance-impact-of-atomicltfloating-pointgtfetch_min_max-semantics" title="Performance impact of atomic<floating-point>::fetch_min/_max semantics">Performance impact of atomic&lt;floating-point&gt;::fetch_min/_max semantics</a></li>
</ul>
</li>
<li><a href="#Design-space" title="Design space">Design space</a></li>
<li><a href="#Wording" title="Wording">Wording</a></li>
<li class=""><a href="#References" title="References">References</a></li>
</ul>
</div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
            </ul>
        </div>
    </div>
    <div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;"  >
        <div class="toc"><ul class="nav">
<li><a href="#Atomic-floating-point-minmax" title="Atomic floating-point min/max">Atomic floating-point min/max</a></li>
<li><a href="#Changelog" title="Changelog">Changelog</a></li>
<li><a href="#Introduction" title="Introduction">Introduction</a></li>
<li><a href="#Survey-of-programming-language-floating-point-minmax-API-semantics" title="Survey of programming language floating-point min/max API semantics">Survey of programming language floating-point min/max API semantics</a><ul class="nav">
<li><a href="#C-stdminstdmax" title="C++ std::min/std::max">C++ std::min/std::max</a></li>
<li><a href="#C-fminfmax" title="C fmin/fmax">C fmin/fmax</a></li>
<li><a href="#C23-minimummaximumminimumNumbermaximumNumber" title="C23 minimum/maximum/minimumNumber/maximumNumber">C23 minimum/maximum/minimumNumber/maximumNumber</a></li>
</ul>
</li>
<li><a href="#Impact-of-replacing-min-with-fminimum_num" title="Impact of replacing min with fminimum_num">Impact of replacing min with fminimum_num</a></li>
<li><a href="#Survey-of-hardware-atomic-floating-point-minmax-API-semantics" title="Survey of hardware atomic floating-point min/max API semantics">Survey of hardware atomic floating-point min/max API semantics</a><ul class="nav">
<li><a href="#Performance-impact-of-atomicltfloating-pointgtfetch_min_max-semantics" title="Performance impact of atomic<floating-point>::fetch_min/_max semantics">Performance impact of atomic&lt;floating-point&gt;::fetch_min/_max semantics</a></li>
</ul>
</li>
<li><a href="#Design-space" title="Design space">Design space</a></li>
<li><a href="#Wording" title="Wording">Wording</a></li>
<li class=""><a href="#References" title="References">References</a></li>
</ul>
</div><div class="toc-menu"><a class="expand-toggle" href="#">Expand all</a><a class="back-to-top" href="#">Back to top</a><a class="go-to-bottom" href="#">Go to bottom</a></div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=" crossorigin="anonymous" defer></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
    <script>
        var markdown = $(".markdown-body");
        //smooth all hash trigger scrolling
        function smoothHashScroll() {
            var hashElements = $("a[href^='#']").toArray();
            for (var i = 0; i < hashElements.length; i++) {
                var element = hashElements[i];
                var $element = $(element);
                var hash = element.hash;
                if (hash) {
                    $element.on('click', function (e) {
                        // store hash
                        var hash = this.hash;
                        if ($(hash).length <= 0) return;
                        // prevent default anchor click behavior
                        e.preventDefault();
                        // animate
                        $('body, html').stop(true, true).animate({
                            scrollTop: $(hash).offset().top
                        }, 100, "linear", function () {
                            // when done, add hash to url
                            // (default click behaviour)
                            window.location.hash = hash;
                        });
                    });
                }
            }
        }

        smoothHashScroll();
        var toc = $('.ui-toc');
        var tocAffix = $('.ui-affix-toc');
        var tocDropdown = $('.ui-toc-dropdown');
        //toc
        tocDropdown.click(function (e) {
            e.stopPropagation();
        });

        var enoughForAffixToc = true;

        function generateScrollspy() {
            $(document.body).scrollspy({
                target: ''
            });
            $(document.body).scrollspy('refresh');
            if (enoughForAffixToc) {
                toc.hide();
                tocAffix.show();
            } else {
                tocAffix.hide();
                toc.show();
            }
            $(document.body).scroll();
        }

        function windowResize() {
            //toc right
            var paddingRight = parseFloat(markdown.css('padding-right'));
            var right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight));
            toc.css('right', right + 'px');
            //affix toc left
            var newbool;
            var rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2;
            //for ipad or wider device
            if (rightMargin >= 133) {
                newbool = true;
                var affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2;
                var left = markdown.offset().left + markdown.outerWidth() - affixLeftMargin;
                tocAffix.css('left', left + 'px');
            } else {
                newbool = false;
            }
            if (newbool != enoughForAffixToc) {
                enoughForAffixToc = newbool;
                generateScrollspy();
            }
        }
        $(window).resize(function () {
            windowResize();
        });
        $(document).ready(function () {
            windowResize();
            generateScrollspy();
        });

        //remove hash
        function removeHash() {
            window.location.hash = '';
        }

        var backtotop = $('.back-to-top');
        var gotobottom = $('.go-to-bottom');

        backtotop.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            if (scrollToTop)
                scrollToTop();
            removeHash();
        });
        gotobottom.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            if (scrollToBottom)
                scrollToBottom();
            removeHash();
        });

        var toggle = $('.expand-toggle');
        var tocExpand = false;

        checkExpandToggle();
        toggle.click(function (e) {
            e.preventDefault();
            e.stopPropagation();
            tocExpand = !tocExpand;
            checkExpandToggle();
        })

        function checkExpandToggle () {
            var toc = $('.ui-toc-dropdown .toc');
            var toggle = $('.expand-toggle');
            if (!tocExpand) {
                toc.removeClass('expand');
                toggle.text('Expand all');
            } else {
                toc.addClass('expand');
                toggle.text('Collapse all');
            }
        }

        function scrollToTop() {
            $('body, html').stop(true, true).animate({
                scrollTop: 0
            }, 100, "linear");
        }

        function scrollToBottom() {
            $('body, html').stop(true, true).animate({
                scrollTop: $(document.body)[0].scrollHeight
            }, 100, "linear");
        }
    </script>
</body>

</html>
