结对编程项目报告--四则运算CORE
<!doctype html>
sw_lab2.mdhtml {overflow-x: initial !important;}#write, body { height: auto; }
#write, #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write ol, #write p, #write ul { position: relative; }
#write, #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p, #write pre { width: inherit; }
#write, pre { white-space: pre-wrap; }
.CodeMirror, .md-fences, table { text-align: left; }
.md-reset, a:active, a:hover { outline: 0px; }
.md-reset, .md-toc-item a { text-decoration: none; }
.MathJax_SVG, .md-reset { float: none; direction: ltr; }
:root { --bg-color:#ffffff; --text-color:#333333; }
html { font-size: 14px; background-color: var(--bg-color); color: var(--text-color); font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; }
body { margin: 0px; padding: 0px; bottom: 0px; top: 0px; left: 0px; right: 0px; font-size: 1rem; line-height: 1.42857; overflow-x: hidden; background: inherit; }
.in-text-selection, ::selection { background: rgb(181, 214, 252); text-shadow: none; }
#write { margin: 0px auto; word-break: normal; word-wrap: break-word; padding-bottom: 70px; overflow-x: visible; }
.first-line-indent #write p .md-line { text-indent: 0px; }
.first-line-indent #write li, .first-line-indent #write p, .first-line-indent #write p .md-line:first-child { text-indent: 2em; }
.for-image #write { padding-left: 8px; padding-right: 8px; }
body.typora-export { padding-left: 30px; padding-right: 30px; }
@media screen and (max-width: 500px) {
body.typora-export { padding-left: 0px; padding-right: 0px; }
.CodeMirror-sizer { margin-left: 0px !important; }
.CodeMirror-gutters { display: none !important; }
}
#write > blockquote:first-child, #write > div:first-child, #write > ol:first-child, #write > p:first-child, #write > pre:first-child, #write > table:first-child, #write > ul:first-child { margin-top: 30px; }
#write li > table:first-child { margin-top: -20px; }
img { max-width: 100%; vertical-align: middle; }
button, input, select, textarea { color: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; }
input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
*, ::after, ::before { box-sizing: border-box; }
h1 { font-size: 2rem; }
h2 { font-size: 1.8rem; }
h3 { font-size: 1.6rem; }
h4 { font-size: 1.4rem; }
h5 { font-size: 1.2rem; }
h6 { font-size: 1rem; }
p { -webkit-margin-before: 1rem; -webkit-margin-after: 1rem; -webkit-margin-start: 0px; -webkit-margin-end: 0px; }
.mathjax-block { margin-top: 0px; margin-bottom: 0px; -webkit-margin-before: 0px; -webkit-margin-after: 0px; }
.hidden { display: none; }
.md-blockmeta { color: rgb(204, 204, 204); font-weight: 700; font-style: italic; }
a { cursor: pointer; }
sup.md-footnote { padding: 2px 4px; background-color: rgba(238, 238, 238, 0.7); color: rgb(85, 85, 85); border-radius: 4px; }
#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; }
#write > figure:first-child { margin-top: 16px; }
figure { overflow-x: auto; margin: -8px 0px 0px -8px; max-width: calc(100% + 16px); padding: 8px; }
tr { break-inside: avoid; break-after: auto; }
thead { display: table-header-group; }
table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; }
.CodeMirror-line, .md-fences { break-inside: avoid; }
table.md-table td { min-width: 80px; }
.CodeMirror-gutters { border-right: 0px; background-color: inherit; margin-right: 4px; }
.CodeMirror-placeholder { opacity: 0.3; }
.CodeMirror pre { padding: 0px 4px; }
.CodeMirror-lines { padding: 0px; }
div.hr:focus { cursor: none; }
.md-fences { font-size: 0.9rem; display: block; overflow: visible; white-space: pre; background: inherit; position: relative !important; }
.md-diagram-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; }
.md-fences .CodeMirror.CodeMirror-wrap { top: -1.6em; margin-bottom: -1.6em; }
.md-fences.mock-cm { white-space: pre-wrap; }
.show-fences-line-number .md-fences { padding-left: 0px; }
.show-fences-line-number .md-fences.mock-cm { padding-left: 40px; }
.footnotes { opacity: 0.8; font-size: 0.9rem; margin-top: 1em; margin-bottom: 1em; }
.footnotes + .footnotes { margin-top: 0px; }
.md-reset { margin: 0px; padding: 0px; border: 0px; vertical-align: top; background: 0px 0px; text-shadow: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; -webkit-tap-highlight-color: transparent; line-height: normal; font-weight: 400; text-align: left; box-sizing: content-box; }
.md-toc-inner, a img, img a { cursor: pointer; }
li div { padding-top: 0px; }
blockquote { margin: 1rem 0px; }
li .mathjax-block, li p { margin: 0.5rem 0px; }
li { margin: 0px; position: relative; }
blockquote > :last-child { margin-bottom: 0px; }
blockquote > :first-child { margin-top: 0px; }
.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; white-space: nowrap; }
@media print {
body, html { border: 1px solid transparent; height: 99%; break-after: avoid; break-before: avoid; }
#write { margin-top: 0px; border-color: transparent !important; }
.typora-export * { -webkit-print-color-adjust: exact; }
h1, h2, h3, h4, h5, h6 { break-after: avoid-page; orphans: 2; }
p { orphans: 4; }
html.blink-to-pdf { font-size: 13px; }
.typora-export #write { padding-left: 1cm; padding-right: 1cm; padding-bottom: 0px; break-after: avoid; }
.typora-export #write::after { height: 0px; }
@page { margin: 20mm 0px; }
}
.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
pre.md-meta-block { font-size: 0.8rem; min-height: 0.8rem; white-space: pre-wrap; background: rgb(204, 204, 204); display: block; overflow-x: hidden; }
p > img:only-child { display: block; margin: auto; }
.md-line > .md-image:only-child, p > .md-image:only-child { display: inline-block; width: 100%; text-align: center; }
.mathjax-block:not(:empty)::after, .md-toc-content::after, .md-toc::after { display: none; }
#write .MathJax_Display { margin: 0.8em 0px 0px; }
.mathjax-block { white-space: pre; overflow: hidden; width: 100%; }
p + .mathjax-block { margin-top: -1.143rem; }
[contenteditable="true"]:active, [contenteditable="true"]:focus { outline: 0px; box-shadow: none; }
.md-task-list-item { position: relative; list-style-type: none; }
.task-list-item.md-task-list-item { padding-left: 0px; }
.md-task-list-item > input { position: absolute; top: 0px; left: 0px; margin-left: -1.2em; margin-top: calc(1em - 10px); }
.math { font-size: 1rem; }
.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-radius: 10px; }
.MathJax_SVG, .mathjax-block .MathJax_SVG_Display { text-indent: 0px; max-width: none; max-height: none; min-height: 0px; }
.md-toc-content { position: relative; margin-left: 0px; }
.md-toc-item { display: block; color: rgb(65, 131, 196); }
.md-toc-inner:hover { }
.md-toc-inner { display: inline-block; }
.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: 700; }
.md-toc-h2 .md-toc-inner { margin-left: 2em; }
.md-toc-h3 .md-toc-inner { margin-left: 4em; }
.md-toc-h4 .md-toc-inner { margin-left: 6em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 .md-toc-inner { margin-left: 10em; }
@media screen and (max-width: 48em) {
.md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
.md-toc-h4 .md-toc-inner { margin-left: 5em; }
.md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
.md-toc-h6 .md-toc-inner { margin-left: 8em; }
}
a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; }
.footnote-line a:not(.reversefootnote) { color: inherit; }
.md-attr { display: none; }
.md-fn-count::after { content: "."; }
code, pre, tt { font-family: var(--monospace); }
.md-comment { color: rgb(162, 127, 3); opacity: 0.8; font-family: var(--monospace); }
code { text-align: left; }
a.md-print-anchor { border-width: initial !important; border-style: none !important; border-color: initial !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: 0px !important; background: 0px 0px !important; text-decoration: initial !important; text-shadow: initial !important; }
.md-inline-math .MathJax_SVG .noError { display: none !important; }
.mathjax-block .MathJax_SVG_Display { text-align: center; margin: 1em 0px; position: relative; min-width: 100%; width: auto; display: block !important; }
.MathJax_SVG_Display, .md-inline-math .MathJax_SVG_Display { width: auto; margin: inherit; display: inline-block !important; }
.MathJax_SVG .MJX-monospace { font-family: monospace; }
.MathJax_SVG .MJX-sans-serif { font-family: sans-serif; }
.MathJax_SVG { display: inline; font-style: normal; font-weight: 400; line-height: normal; zoom: 90%; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; min-width: 0px; border: 0px; padding: 0px; margin: 0px; }
.MathJax_SVG * { transition: none; }
.os-windows.monocolor-emoji .md-emoji { font-family: "Segoe UI Symbol", sans-serif; }
.md-diagram-panel > svg, [lang="flow"] svg, [lang="mermaid"] svg { max-width: 100%; }
[lang="mermaid"] .node text { font-size: 1rem; }
table tr th { border-bottom: 0px; }
.CodeMirror, .CodeMirror-sizer { position: relative; }
.CodeMirror.cm-s-inner { background: inherit; }
.fences-no-line-wrapping .md-fences .CodeMirror { margin-top: -30px; }
.CodeMirror-scroll { overflow-y: hidden; overflow-x: auto; }
.CodeMirror-lines { padding: 4px 0px; }
.CodeMirror-gutter-filler, .CodeMirror-scrollbar-filler { background-color: rgb(255, 255, 255); }
.CodeMirror-scroll, .cm-s-inner .CodeMirror-activeline-background { background: inherit; }
.CodeMirror-linenumber { padding: 0px 3px 0px 5px; text-align: right; color: rgb(153, 153, 153); }
.cm-s-inner .cm-keyword { color: rgb(119, 0, 136); }
.cm-s-inner .cm-atom, .cm-s-inner.cm-atom { color: rgb(34, 17, 153); }
.cm-s-inner .cm-number { color: rgb(17, 102, 68); }
.cm-s-inner .cm-def { color: rgb(0, 0, 255); }
.cm-s-inner .cm-variable { color: rgb(0, 0, 0); }
.cm-s-inner .cm-variable-2 { color: rgb(0, 85, 170); }
.cm-s-inner .cm-variable-3 { color: rgb(0, 136, 85); }
.cm-s-inner .cm-string { color: rgb(170, 17, 17); }
.cm-s-inner .cm-property { color: rgb(0, 0, 0); }
.cm-s-inner .cm-operator { color: rgb(152, 26, 26); }
.cm-s-inner .cm-comment, .cm-s-inner.cm-comment { color: rgb(170, 85, 0); }
.cm-s-inner .cm-string-2 { color: rgb(255, 85, 0); }
.cm-s-inner .cm-meta, .cm-s-inner .cm-qualifier { color: rgb(85, 85, 85); }
.cm-s-inner .cm-builtin { color: rgb(51, 0, 170); }
.cm-s-inner .cm-bracket { color: rgb(153, 153, 119); }
.cm-s-inner .cm-tag { color: rgb(17, 119, 0); }
.cm-s-inner .cm-attribute { color: rgb(0, 0, 204); }
.cm-s-inner .cm-header, .cm-s-inner.cm-header { color: rgb(0, 0, 255); }
.cm-s-inner .cm-quote, .cm-s-inner.cm-quote { color: rgb(0, 153, 0); }
.cm-s-inner .cm-hr, .cm-s-inner.cm-hr { color: rgb(153, 153, 153); }
.cm-s-inner .cm-link, .cm-s-inner.cm-link { color: rgb(0, 0, 204); }
.cm-negative { color: rgb(221, 68, 68); }
.cm-positive { color: rgb(34, 153, 34); }
.cm-header, .cm-strong { font-weight: 700; }
.cm-del { text-decoration: line-through; }
.cm-em { font-style: italic; }
.cm-link { text-decoration: underline; }
.cm-error, .cm-invalidchar { color: red; }
.cm-constant { color: rgb(38, 139, 210); }
.cm-defined { color: rgb(181, 137, 0); }
div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); }
div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); }
.CodeMirror { height: auto; overflow: hidden; }
.CodeMirror-scroll { margin-bottom: -30px; padding-bottom: 30px; height: 100%; outline: 0px; position: relative; box-sizing: content-box; }
.CodeMirror-gutter-filler, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-vscrollbar { position: absolute; z-index: 6; display: none; }
.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow-x: hidden; overflow-y: scroll; }
.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow-y: hidden; overflow-x: scroll; }
.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; }
.CodeMirror-gutter-filler { left: 0px; bottom: 0px; }
.CodeMirror-gutters { border-right: 1px solid rgb(221, 221, 221); background: inherit; white-space: nowrap; position: absolute; left: 0px; top: 0px; padding-bottom: 30px; z-index: 3; }
.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; }
.CodeMirror-gutter-wrapper { position: absolute; z-index: 4; background: 0px 0px !important; border: none !important; }
.CodeMirror-gutter-background { position: absolute; top: 0px; bottom: 0px; z-index: 4; }
.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; }
.CodeMirror-lines { cursor: text; }
.CodeMirror pre { border-radius: 0px; border-width: 0px; background: 0px 0px; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; word-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; }
.CodeMirror-wrap pre { word-wrap: break-word; white-space: pre-wrap; word-break: normal; }
.CodeMirror-code pre { border-right: 30px solid transparent; width: fit-content; }
.CodeMirror-wrap .CodeMirror-code pre { border-right: none; width: auto; }
.CodeMirror-linebackground { position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 0; }
.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; }
.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; }
.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; }
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor { position: absolute; border-right: none; width: 0px; visibility: hidden; }
.CodeMirror-focused div.CodeMirror-cursor { visibility: inherit; }
.CodeMirror-selected { background: rgb(217, 217, 217); }
.CodeMirror-focused .CodeMirror-selected { background: rgb(215, 212, 240); }
.cm-searching { background: rgba(255, 255, 0, 0.4); }
@media print {
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
}
.CodeMirror-lint-markers { width: 16px; }
.CodeMirror-lint-tooltip { background-color: infobackground; border: 1px solid rgb(0, 0, 0); border-radius: 4px; color: infotext; font-family: var(--monospace); overflow: hidden; padding: 2px 5px; position: fixed; white-space: pre-wrap; z-index: 10000; max-width: 600px; opacity: 0; transition: opacity 0.4s; font-size: 0.8em; }
.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { background-position: left bottom; background-repeat: repeat-x; }
.CodeMirror-lint-mark-error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg=="); }
.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { background-position: center center; background-repeat: no-repeat; cursor: pointer; display: inline-block; height: 16px; width: 16px; vertical-align: middle; position: relative; }
.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { padding-left: 18px; background-position: left top; background-repeat: no-repeat; }
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); }
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); }
.CodeMirror-lint-marker-multiple { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); background-repeat: no-repeat; background-position: right bottom; width: 100%; height: 100%; }
:root { --side-bar-bg-color: #fafafa; --control-text-color: #777; }
@font-face { font-family: "Open Sans"; font-style: normal; font-weight: normal; src: local("Open Sans Regular"), url("./github/400.woff") format("woff"); }
@font-face { font-family: "Open Sans"; font-style: italic; font-weight: normal; src: local("Open Sans Italic"), url("./github/400i.woff") format("woff"); }
@font-face { font-family: "Open Sans"; font-style: normal; font-weight: bold; src: local("Open Sans Bold"), url("./github/700.woff") format("woff"); }
@font-face { font-family: "Open Sans"; font-style: italic; font-weight: bold; src: local("Open Sans Bold Italic"), url("./github/700i.woff") format("woff"); }
html { font-size: 16px; }
body { font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; color: rgb(51, 51, 51); line-height: 1.6; }
#write { max-width: 860px; margin: 0px auto; padding: 20px 30px 100px; }
#write > ul:first-child, #write > ol:first-child { margin-top: 30px; }
body > :first-child { margin-top: 0px !important; }
body > :last-child { margin-bottom: 0px !important; }
a { color: rgb(65, 131, 196); }
h1, h2, h3, h4, h5, h6 { position: relative; margin-top: 1rem; margin-bottom: 1rem; font-weight: bold; line-height: 1.4; cursor: text; }
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { text-decoration: none; }
h1 tt, h1 code { font-size: inherit; }
h2 tt, h2 code { font-size: inherit; }
h3 tt, h3 code { font-size: inherit; }
h4 tt, h4 code { font-size: inherit; }
h5 tt, h5 code { font-size: inherit; }
h6 tt, h6 code { font-size: inherit; }
h1 { padding-bottom: 0.3em; font-size: 2.25em; line-height: 1.2; border-bottom: 1px solid rgb(238, 238, 238); }
h2 { padding-bottom: 0.3em; font-size: 1.75em; line-height: 1.225; border-bottom: 1px solid rgb(238, 238, 238); }
h3 { font-size: 1.5em; line-height: 1.43; }
h4 { font-size: 1.25em; }
h5 { font-size: 1em; }
h6 { font-size: 1em; color: rgb(119, 119, 119); }
p, blockquote, ul, ol, dl, table { margin: 0.8em 0px; }
li > ol, li > ul { margin: 0px; }
hr { height: 4px; padding: 0px; margin: 16px 0px; background-color: rgb(231, 231, 231); border-width: 0px 0px 1px; border-style: none none solid; border-top-color: initial; border-right-color: initial; border-left-color: initial; border-image: initial; overflow: hidden; box-sizing: content-box; border-bottom-color: rgb(221, 221, 221); }
body > h2:first-child { margin-top: 0px; padding-top: 0px; }
body > h1:first-child { margin-top: 0px; padding-top: 0px; }
body > h1:first-child + h2 { margin-top: 0px; padding-top: 0px; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child { margin-top: 0px; padding-top: 0px; }
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 { margin-top: 0px; padding-top: 0px; }
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p { margin-top: 0px; }
li p.first { display: inline-block; }
ul, ol { padding-left: 30px; }
ul:first-child, ol:first-child { margin-top: 0px; }
ul:last-child, ol:last-child { margin-bottom: 0px; }
blockquote { border-left: 4px solid rgb(221, 221, 221); padding: 0px 15px; color: rgb(119, 119, 119); }
blockquote blockquote { padding-right: 0px; }
table { padding: 0px; word-break: initial; }
table tr { border-top: 1px solid rgb(204, 204, 204); margin: 0px; padding: 0px; }
table tr:nth-child(2n) { background-color: rgb(248, 248, 248); }
table tr th { font-weight: bold; border-width: 1px 1px 0px; border-top-style: solid; border-right-style: solid; border-left-style: solid; border-top-color: rgb(204, 204, 204); border-right-color: rgb(204, 204, 204); border-left-color: rgb(204, 204, 204); border-image: initial; border-bottom-style: initial; border-bottom-color: initial; text-align: left; margin: 0px; padding: 6px 13px; }
table tr td { border: 1px solid rgb(204, 204, 204); text-align: left; margin: 0px; padding: 6px 13px; }
table tr th:first-child, table tr td:first-child { margin-top: 0px; }
table tr th:last-child, table tr td:last-child { margin-bottom: 0px; }
.CodeMirror-gutters { border-right: 1px solid rgb(221, 221, 221); }
.md-fences, code, tt { border: 1px solid rgb(221, 221, 221); background-color: rgb(248, 248, 248); border-radius: 3px; font-family: Consolas, "Liberation Mono", Courier, monospace; padding: 2px 4px 0px; font-size: 0.9em; }
.md-fences { margin-bottom: 15px; margin-top: 15px; padding: 8px 1em 6px; }
.md-task-list-item > input { margin-left: -1.3em; }
@media screen and (min-width: 914px)
@media print {
html { font-size: 13px; }
table, pre { break-inside: avoid; }
pre { word-wrap: break-word; }
}
.md-fences { background-color: rgb(248, 248, 248); }
#write pre.md-meta-block { padding: 1rem; font-size: 85%; line-height: 1.45; background-color: rgb(247, 247, 247); border: 0px; border-radius: 3px; color: rgb(119, 119, 119); margin-top: 0px !important; }
.mathjax-block > .code-tooltip { bottom: 0.375rem; }
#write > h3.md-focusbefore { left: -1.5625rem; top: 0.375rem; }
#write > h4.md-focusbefore { left: -1.5625rem; top: 0.285714rem; }
#write > h5.md-focusbefore { left: -1.5625rem; top: 0.285714rem; }
#write > h6.md-focusbefore { left: -1.5625rem; top: 0.285714rem; }
.md-image > .md-meta { border-radius: 3px; font-family: Consolas, "Liberation Mono", Courier, monospace; padding: 2px 0px 0px 4px; font-size: 0.9em; color: inherit; }
.md-tag { color: inherit; }
.md-toc { margin-top: 20px; padding-bottom: 20px; }
.sidebar-tabs { border-bottom: none; }
#typora-quick-open { border: 1px solid rgb(221, 221, 221); background-color: rgb(248, 248, 248); }
#typora-quick-open-item { background-color: rgb(250, 250, 250); border-color: rgb(254, 254, 254) rgb(229, 229, 229) rgb(229, 229, 229) rgb(238, 238, 238); border-style: solid; border-width: 1px; }
#md-notification::before { top: 10px; }
.on-focus-mode blockquote { border-left-color: rgba(85, 85, 85, 0.12); }
header, .context-menu, .megamenu-content, footer { font-family: "Segoe UI", Arial, sans-serif; }
.file-node-content:hover .file-node-icon, .file-node-content:hover .file-node-open-state { visibility: visible; }
.mac-seamless-mode #typora-sidebar { background-color: var(--side-bar-bg-color); }
.md-lang { color: rgb(180, 101, 77); }
.html-for-mac .context-menu { --item-hover-bg-color: #E6F0FE; }
.typora-export p {white-space: normal;}
结对编程项目报告--四则运算CORE
第15组:JL17110067 隆晋威 PB16120853 赵瑞
项目GitHub地址
https://github.com/NiceKingWei/homework2
PSP
status | stages | 预估耗时 | 实际耗时 |
---|---|---|---|
Accepted | make plan | 20 min | 20 min |
Accepted | demand analysis | 40 min | 40 min |
Accepted | analysis | 45 min | 90 min |
Accepted | code | 3 hours | 5 hours |
Accepted | test | 2 hours | 3 hours |
Accepted | report | 1 hours | 2 hours |
Sum | 8 hours | 12 hours |
项目需求
像《构建之法》的人物阿超那样,写一个能自动生成小学四则运算题目并给出答案的命令行 “软件”, 如果我们要把这个功能放到不同的环境中去(例如,命令行,Windows 图形界面程序,网页程序,手机App),就会碰到困难,因为目前代码的普遍问题是代码都散落在main ( )函数或者其他子函数中,我们很难把这些功能完整地剥离出来,作为一个独立的模块满足不同的需求。
API
setting()
function:x1void setting(
2int max_opearators, //操作数的数目最大值
3long max_range, //中间结果和结果的范围,如果是分数,只限制分母和最后结果的值
4int precision, //精度
5int has_fraction, //是否含有分数,1:含有,0:不含有分数
6int has_real) //是否含有小数,1:含有,0:不含有1
7{
8
9if (max_opearators != -1) global_setting.max_opearators = max_opearators;
10if (max_range != -1) global_setting.max_range = max_range;
11if (precision != -1) global_setting.precision = precision;
12if (has_fraction != -1) global_setting.has_fraction = has_fraction;
13if (has_real != -1) global_setting.has_real = has_real;
14global_setting.max_num = max_range / 10;
15}
就是可以多次改变设置,在传入参数的时候,
max_opearators
、max_range
、precision
可以传入值或者-1,传值代表更改该设置,-1代表不变。has_fraction
、has_real
可以传入1,0,-1;1代表开启,0代表没有,-1代表不变。generate
函数:xxxxxxxxxx
11void generate(string* question, string* answer);
将参数传进去,运行后结果就存在了
string* answer
里面。
代码逻辑思路
我们首先定义了 fraction 类,这是分数类,用于符号计算。
xxxxxxxxxx101class fraction {2public:3long numerator, denominator;4void reduction() ;5fraction operator + (const fraction x) const;6fraction operator - (const fraction& x) const;7fraction operator * (const fraction& x) const;8fraction operator / (const fraction& x) const;9fraction operator ^ (fraction x) const;10};
fraction 类里面重载了各个运算函数,并在每次计算结束之后通过类中的reduction()
函数把分数变为最简分数。
然后定义了一些工具函数,如输出函数,判断是否是无效值的函数 is_bad_value
xxxxxxxxxx21bool is_bad_value(const fraction& x);2bool is_bad_value(const double& x);
is_bad_value
是一个判断值是否是坏值的函数。坏值在除零异常时可能会出现,在值超出范围的时候也会出现。坏值具有传递性,坏值和任何值运算的结果都是坏值。这种设计方式的灵感来自函数式语言中的 Maybe Monad
,下面放一下fraction operator / (const fraction x) const;
作为例子:
xxxxxxxxxx171fraction operator / (const fraction& x) const {2if (is_bad_value(*this))return *this;3if (is_bad_value(x))return x;4fraction stan_bad_value(1, 0);5if (x.numerator == 0) {6return stan_bad_value;7}8fraction result;9result.numerator = this->numerator * x.denominator;10result.denominator = this->denominator * x.numerator;11result.reduction();12if (is_bad_value(result)) {13result.numerator = 1;14result.denominator = 0;15}16return result;17}
接下来定义抽象语法树的结构。
xxxxxxxxxx301enum ASTNodeType { TYPE_ADD = 0, TYPE_MINUS = 1, TYPE_MUL = 2, TYPE_DIV = 3, TYPE_POWER = 4, TYPE_FRACTION = 5, TYPE_DOUBLE = 6 };23struct ASTNode;45union NodeData {6fraction frac;7double real;8pair<ASTNode*, ASTNode*> node;910NodeData() {11real = 0;12}13};1415struct ASTNode {16ASTNodeType type;17NodeData data;1819ASTNode() {20type = TYPE_DOUBLE;21}2223~ASTNode() {24if (type != TYPE_FRACTION && type != TYPE_DOUBLE) {25delete data.node.first;26delete data.node.second;27}28}29};30
每一个抽象语法树的节点都包含两个字段,一个是 type,一个是 data。type 的类型是一个枚举值,data 是一个 union 联合体。这种做法的灵感也来自函数式语言。在表示抽象语法树时,tagged union
是一种很好的方式。但因为不确定能不能使用 c++17,所以我们并没有用类型安全的 std::variant
,而是使用了自己定义的tagged union
。
之后的事情就比较简单了
xxxxxxxxxx21ASTNode* random_value(cal_mode mode);2ASTNode* random_ast(cal_mode mode);
这两个函数产生随机值和随机抽象语法树,根据 setting 的规则产生合适的表达式树。
这两个函数的代码:
xxxxxxxxxx641inline ASTNode* random_value(cal_mode mode) {2ASTNode* node = new ASTNode();3int m, n;4switch (mode) {5case MODE_FRACTION:6node->type = TYPE_FRACTION;7m = rand() % (global_setting.max_num - 1) + 1;8n = rand() % (m * 5);9if (global_setting.has_fraction) {10node->data.frac = fraction(n, m);11}12else {13node->data.frac = fraction(m);14}15break;1617case MODE_REAL:18node->type = TYPE_DOUBLE;19double base = pow(10, global_setting.precision);20node->data.real = floor((rand() / (double)RAND_MAX)*global_setting.max_num*base) / base;21break;22}23return node;24}2526ASTNode* random_ast(cal_mode mode) {27int n = global_setting.max_opearators <= 1 ? 1 : rand() % (global_setting.max_opearators - 1) + 1;28ASTNode* num1 = random_value(mode);29for (int i = 0; i<n; i++) {30ASTNode* num2 = random_value(mode);31if (rand() % 2) swap(num1, num2);32int r = rand() % 17;33ASTNode* new_node = new ASTNode();343536if (r-- == 16 && (num2->type == TYPE_FRACTION || num2->type == TYPE_FRACTION) && (num1->type != TYPE_POWER) && global_setting.has_power) {37if (mode == MODE_FRACTION) num2->data.frac = fraction(rand() % 4 + 1);38else num2->data.real = rand() % 2 + 2;3940new_node->type = TYPE_POWER;41new_node->data.node.first = num1;42new_node->data.node.second = num2;43}44else {45if (global_setting.has_mul_div) {46new_node->type = (ASTNodeType)(r / 4);47if (mode == MODE_FRACTION && !global_setting.has_fraction) {48r = rand() % 10;49if (r-- == 9) new_node->type = TYPE_DIV;50else new_node->type = (ASTNodeType)(r / 3);51}52}53else {54new_node->type = (ASTNodeType)(r / 8);55}56new_node->data.node.first = num1;57new_node->data.node.second = num2;58}5960num1 = new_node;61}62return num1;63}64
xxxxxxxxxx21ASTNode* calc_asttree(ASTNode* root);2ASTNode* ast_eval(ASTNode* root);
calc_asttree
是递归函数,它递归调用自身,计算左子树和右子树的值,然后再计算当前节点的值,如果有一个结点的type是TYPE_DOUBLE
,那么返回给上一层的type就是TYPE_DOUBLE
。
这两个函数的代码
xxxxxxxxxx1661long long hash_value;2ASTNode* calc_asttree(ASTNode* root) {3ASTNode* result = new ASTNode();4result->type = TYPE_FRACTION;5result->data.frac;6ASTNode* temp_a = new ASTNode();7ASTNode* temp_b = new ASTNode();8switch (root->type) {9case TYPE_FRACTION:10result->type = TYPE_FRACTION;11result->data.frac = root->data.frac;12break;13case TYPE_DOUBLE:14result->type = TYPE_DOUBLE;15result->data.real = root->data.real;16break;17case TYPE_ADD:18temp_a = calc_asttree(root->data.node.first);19temp_b = calc_asttree(root->data.node.second);20if (temp_a->type == TYPE_FRACTION && temp_b->type == TYPE_FRACTION) {21result->type = TYPE_FRACTION;22result->data.frac = temp_a->data.frac + temp_b->data.frac;23}24else {25result->type = TYPE_DOUBLE;26double a, b;27if (temp_a->type == TYPE_FRACTION) {28a = (double)temp_a->data.frac.numerator / (double)temp_a->data.frac.denominator;29}30else if (temp_a->type == TYPE_DOUBLE) {31a = temp_a->data.real;32}33if (temp_b->type == TYPE_FRACTION) {34b = (double)temp_b->data.frac.numerator / (double)temp_b->data.frac.denominator;35}36else if (temp_b->type == TYPE_DOUBLE) {37b = temp_b->data.real;38}39result->data.real = is_bad_value(a) || is_bad_value(b) ? INFINITY : (a + b);40}41break;42case TYPE_MINUS:43temp_a = calc_asttree(root->data.node.first);44temp_b = calc_asttree(root->data.node.second);45if (temp_a->type == TYPE_FRACTION && temp_b->type == TYPE_FRACTION) {46result->type = TYPE_FRACTION;47result->data.frac = temp_a->data.frac - temp_b->data.frac;4849}50else {51result->type = TYPE_DOUBLE;52double a, b;53if (temp_a->type == TYPE_FRACTION) {54a = (double)temp_a->data.frac.numerator / (double)temp_a->data.frac.denominator;55}56else if (temp_a->type == TYPE_DOUBLE) {57a = temp_a->data.real;58}59if (temp_b->type == TYPE_FRACTION) {60b = (double)temp_b->data.frac.numerator / (double)temp_b->data.frac.denominator;61}62else if (temp_b->type == TYPE_DOUBLE) {63b = temp_b->data.real;64}65result->data.real = is_bad_value(a) || is_bad_value(b) ? INFINITY : (a - b);66}67break;68case TYPE_MUL:69temp_a = calc_asttree(root->data.node.first);70temp_b = calc_asttree(root->data.node.second);71if (temp_a->type == TYPE_FRACTION && temp_b->type == TYPE_FRACTION) {72result->type = TYPE_FRACTION;73result->data.frac = temp_a->data.frac * temp_b->data.frac;7475}76else {77result->type = TYPE_DOUBLE;78double a, b;79if (temp_a->type == TYPE_FRACTION) {80a = (double)temp_a->data.frac.numerator / (double)temp_a->data.frac.denominator;81}82else if (temp_a->type == TYPE_DOUBLE) {83a = temp_a->data.real;84}85if (temp_b->type == TYPE_FRACTION) {86b = (double)temp_b->data.frac.numerator / (double)temp_b->data.frac.denominator;87}88else if (temp_b->type == TYPE_DOUBLE) {89b = temp_b->data.real;90}91result->data.real = is_bad_value(a) || is_bad_value(b) ? INFINITY : (a*b);92}93break;94case TYPE_DIV:95temp_a = calc_asttree(root->data.node.first);96temp_b = calc_asttree(root->data.node.second);97if (temp_a->type == TYPE_FRACTION && temp_b->type == TYPE_FRACTION) {98result->type = TYPE_FRACTION;99result->data.frac = temp_a->data.frac / temp_b->data.frac;100101}102else {103result->type = TYPE_DOUBLE;104double a, b;105if (temp_a->type == TYPE_FRACTION) {106a = (double)temp_a->data.frac.numerator / (double)temp_a->data.frac.denominator;107}108else if (temp_a->type == TYPE_DOUBLE) {109a = temp_a->data.real;110}111if (temp_b->type == TYPE_FRACTION) {112b = (double)temp_b->data.frac.numerator / (double)temp_b->data.frac.denominator;113}114else if (temp_b->type == TYPE_DOUBLE) {115b = temp_b->data.real;116}117result->data.real = is_bad_value(a) || is_bad_value(b) || fabs(b) <= 1e-3 ? INFINITY : (a / b);118}119break;120case TYPE_POWER:121temp_a = calc_asttree(root->data.node.first);122temp_b = calc_asttree(root->data.node.second);123if (temp_a->type == TYPE_FRACTION && temp_b->type == TYPE_FRACTION) {124result->type = TYPE_FRACTION;125result->data.frac = temp_a->data.frac ^ temp_b->data.frac;126127}128else {129result->type = TYPE_DOUBLE;130double a, b;131if (temp_a->type == TYPE_FRACTION) {132a = (double)temp_a->data.frac.numerator / (double)temp_a->data.frac.denominator;133}134else if (temp_a->type == TYPE_DOUBLE) {135a = temp_a->data.real;136}137if (temp_b->type == TYPE_FRACTION) {138b = (double)temp_b->data.frac.numerator / (double)temp_b->data.frac.denominator;139}140else if (temp_b->type == TYPE_DOUBLE) {141b = temp_b->data.real;142}143result->data.real = is_bad_value(a) || is_bad_value(b) ? INFINITY : powl(a, b);144}145break;146}147long long value = (long long)(root->type == TYPE_FRACTION ? (root->data.frac.numerator / (double)root->data.frac.denominator) : root->data.real);148hash_value = (hash_value * 19260817 + value) % (long long)(1e9 + 7);149delete temp_a;150delete temp_b;151if (result->type == TYPE_FRACTION) {152if ( (result->data.frac.denominator > global_setting.max_range*100 || result->data.frac.numerator < 0) ||153(result->data.frac.denominator != 1 && !global_setting.has_fraction)) {154result->data.frac.numerator = 1;155result->data.frac.denominator = 0;156}157} else if (result->type == TYPE_DOUBLE && (result->data.real <0|| result->data.real>global_setting.max_range*10)) {158result->data.real = INFINITY;159}160return result;161}162163ASTNode* ast_eval(ASTNode* root) {164hash_value = 0;165return calc_asttree(root);166}
ast_eval
是调用 calc_asttree
的函数,它先把 hash_code
设为0,然后调用 calc_asttree
在calc_asttree
递归计算的过程中会产生一个操作序列,这个序列可以刻画当前表达式的特征,例如 1+2+3,在计算过程中产生的序列是 1+2=3, 3+3 =6,3+(2+1) 在计算过程中产生的序列为 2+1=3,3+3=6。若定义两个序列等价当前仅当序列中每个算式在交换律意义下等价。可以发现,题目要求的 “重复” 条件与计算序列的等价条件是等价的。因此,我们可以用计算序列来去重。
但计算序列的储存比较占空间,因此我们选择了一个哈希函数,对计算序列进行哈希映射。因为两个序列哈希值相同是两个序列重复的必要条件。因此在实际操作中,只需要两个序列哈希函数不同,则这两个表达式必然不相等。
接下来是表达式输出函数。
xxxxxxxxxx131/*2* Expr := AddExpr | Expr + AddExpr3* AddExpr := MulExpr | AddExpr * MulExpr4* MulExpr := PowExpr | MulExpr ^ PowExpr5* PowExpr := Number | (Expr)6*/7enum ExprType { EXPR_EXPR, EXPR_ADDEXPR, EXPR_MULEXPR, EXPR_POWEXPR };89void ast_output_expr(ASTNode* root, stringstream& ss);10void ast_output_addexpr(ASTNode* root, stringstream& ss);11void ast_output_mulexpr(ASTNode* root, stringstream& ss);12void ast_output_powexpr(ASTNode* root, stringstream& ss);13void ast_output_number(ASTNode* root, stringstream& ss);
注释中的内容是我们的计算表达式的 BNF 范式。由语法产生式,我们可以很容易地写出以上递归函数,并通过函数间的互相调用完成对表达式的输出,这种输出方式不会产生多余的括号。
xxxxxxxxxx11void generate(string* question, string* answer);
generate 函数生成题目和答案。它先调用 random_ast
生成一颗随机语法树,然后对它进行求值,如果结果是坏值,那就重新生成一个。
特别值得一提的是我们的 main
函数
xxxxxxxxxx181int main() {2FILE* file = NULL;3const long long test_num = 100000;4const long long test_groups = 100;5for (long long i = 0; i<test_num; i++) {6if (i % (test_num / test_groups) == 0) {7stringstream ss;8ss << "test" << i / (test_num / test_groups) << ".py";9if (file) fclose(file);10file = fopen(ss.str().c_str(), "w");11}12string que, ans;13generate(&que, &ans);14fprintf(file, "assert(%lld>=0 and abs((%s)-(%s))<5e-2)\n", i, que.c_str(), ans.c_str());15}16fclose(file);17return 0;18}
它为每一组数据生成了一行 python 代码,是一句断言。只要断言成立,这组数据就是正确的。只需要简单改改更改参数,我们就可以获得很多组数据,并能通过脚本进行自动测试。
xxxxxxxxxx111import os2import time3os.system("g++ core.cpp -O2 -g")4print("compile done.")5time.sleep(1);6os.system("./a.out")7time.sleep(1);8print("generate done.")9for i in range(0,100):10os.system("pypy test%d.py" % i)11print("test%d done." % i)
发布前,我们组一共测试了 500万 组数据,均没有出错。
BUG记录
出现了错误的计算结果:
- bug原因:我们俩搞错了乘方和乘法的运算优先级,
- 这个不太容易避免,出错了时候我们还疑问到底该先算乘方还是从左到右乘
- 大概四十分钟,找到错误样例,研究错误样例就可以了,发现了是逻辑错误,那么改代码就可以了。
第二次出现了错误的结果:
- bug原因:分数运算的中间结果分子溢出了long long的范围
- 这个bug是在写函数时候错误的估计了可能用到的范围,没有加强函数的鲁棒性。
- 调试方法:用错误样例逐步测试,观察中间结果。
- 这种鲁棒性的东西,该加还是加上,尽量不要假设前提。
结对编程与个人作业差异
最初,隆晋威同学扮演驾驶员角色,赵瑞同学扮演领航员角色。
在完成整个程序的框架后,分工完成模块细节和测试,互相做驾驶员和领航员,在整个程序写完后,一起测试这个程序,并debug。
一个人用git很随意,可是两个人的话,就要提前看一下队友的修改。
个人看法
结对编程过程中,两个人的作息一致性很重要,在刚写完程序的时候,不出意外出了错误结果,我们开始debug,主要的debug任务是在凌晨完成的。debug到晚上十二点,1000组数据跑对了,后来加到10000又出错了,我们又debug到1点,10000没问题的时候,当时已经凌晨两点了,如果两个人有一个不习惯熬夜的话,这还真有点不舒服了,还好我俩都很不养生。
两个人的debug的速度果然不是1+1=2的简单加法,速度比一个人debug要快得多。
还有就是一起工作在有进展的时候两个人会一起觉得很开心,分享一下喜悦,比一个人有进展自己内心爽一下还happy,比如亮点debug完我们以为大功告成了就很开心(然而第二天加大测试量又出现了新的错误样例)。
结对编程过程中学习的速度时迅速的,这一次结对编程我向隆晋威同学学到了很多,比如代码规范,GitHub的使用和visual studio code的使用,还有用脚本来测试程序。
会选择结对编程用于解决部分任务。
工作时刻
代码
1/*2* core.cpp3* author:4* PB16120853 赵瑞5* JL17110067 隆晋威6* date:7* 2018/4/58*/9#define CORE15_API10#define TEST1112#include <iostream>13#include <string>14#include <cstdio>15#include <tuple>16#include <cmath>17#include <sstream>18#include <set>1920using namespace std;2122/*23* global setting24*/25struct settings {26int max_opearators = 5;27long max_num = 100; // max_range / 1028long max_range = 1000;29int precision = 2;30bool has_fraction = true;31bool has_real = true;32bool has_mul_div = true;33bool has_power = true;34};35settings global_setting;363738/*39* fraction40*/41class fraction;42bool is_bad_value(const fraction& x);43bool is_bad_value(const double& x);44454647class fraction {48private:49long gcd(long u, long v) {50if (!(u&&v)) {51return 1;52}53while (v != 0) {54long r = u % v;55u = v;56v = r;57}58return u;59}60public:61long numerator, denominator;626364fraction(long m = 1, long n = 1) {65this->numerator = m;66this->denominator = n;67this->reduction();68}6970void reduction() {71long x = gcd(this->numerator, this->denominator);72if ((llabs(this->denominator) > global_setting.max_range) || (llabs(this->numerator) > global_setting.max_range)) {73this->numerator = 1;74this->denominator = 0;75x = 1;76}77this->numerator /= x;78this->denominator /= x;79if (this->denominator < 0) {80this->numerator *= -1;81this->denominator *= -1;82}83if (!this->numerator) {84this->denominator = 1;85}86if (!this->denominator) {87this->numerator = 1;88}89if ((abs(this->denominator)>global_setting.max_range) || (abs(this->numerator) > global_setting.max_range)) {90this->numerator = 1;91this->denominator = 0;92}93return;94}9596fraction operator + (const fraction x) const {97if (is_bad_value(*this))return *this;98if (is_bad_value(x))return x;99fraction result;100result.numerator = this->numerator * x.denominator + this->denominator * x.numerator;101result.denominator = this->denominator * x.denominator;102result.reduction();103return result;104}105106107fraction operator - (const fraction& x) const {108if (is_bad_value(*this))return *this;109if (is_bad_value(x))return x;110fraction result;111result.numerator = this->numerator * x.denominator - this->denominator * x.numerator;112result.denominator = this->denominator * x.denominator;113result.reduction();114return result;115}116117fraction operator * (const fraction& x) const {118if (is_bad_value(*this))return *this;119if (is_bad_value(x))return x;120fraction result;121result.numerator = this->numerator * x.numerator;122result.denominator = this->denominator * x.denominator;123result.reduction();124return result;125}126127fraction operator / (const fraction& x) const {128if (is_bad_value(*this))return *this;129if (is_bad_value(x))return x;130fraction stan_bad_value(1, 0);131if (x.numerator == 0) {132return stan_bad_value;133}134fraction result;135result.numerator = this->numerator * x.denominator;136result.denominator = this->denominator * x.numerator;137result.reduction();138if (is_bad_value(result)) {139result.numerator = 1;140result.denominator = 0;141}142return result;143}144145fraction operator ^ (fraction x) const {146if (is_bad_value(*this))return *this;147if (is_bad_value(x))return x;148149x.reduction();150if (x.denominator != 1) {151fraction bad_value;152bad_value.numerator = 1;153bad_value.denominator = 0;154return bad_value;155}156long index = x.numerator;157158fraction result;159result.numerator = (long)powl(this->numerator, abs(index));160result.denominator = (long)powl(this->denominator, abs(index));161if (index < 0) {162long temp;163temp = result.numerator;164result.numerator = result.denominator;165result.denominator = temp;166}167result.reduction();168return result;169}170};171172ostream& operator << (ostream& out, const fraction& frac) {173#ifdef DEBUG174out << '(' << frac.numerator << ".0/" << frac.denominator << ".0)";175return out;176#else177long long n = frac.numerator;178long long d = frac.denominator;179long long integer = n / d;180long long f = n % d;181182if (f == 0) {183out << integer;184}185else {186if (integer) {187out << integer << '\'' << f << '/' << d;188}189else {190out << f << '/' << d;191}192}193return out;194195#endif196}197198/*199* unit test for fraction200*/201void fraction_test() {202fraction a(1, 0), b(0, 1), c(2, 3), d(5, 6), e(8, 4), g(18, 9);203fraction x;204x = a + b;205x = a * b;206x = a - b;207x = a / b;208x = a / c;209x = a + c;210x = a * c;211x = a - c;212x = b + c;213x = b - c;214x = b * c;215x = b / c;216x = c * d;217x = c / d;218x = c + d;219x = c - d;220x = a ^ b;221x = a ^ c;222x = a ^ d;223x = a ^ e;224x = a ^ g;225x = b ^ c;226x = b ^ a;227x = b ^ d;228x = b ^ e;229x = b ^ g;230x = e * g;231x = e - g;232x = e + g;233x = e / g;234}235236/*237* is_bad_value238*/239bool is_bad_value(const fraction& x) {240if (!x.denominator) {241return true;242}243else {244return false;245}246}247248bool is_bad_value(const double& x) {249// todo: error250if (isnan(x) || isinf(x)) {251return true;252}253else {254return false;255}256}257258/*259* AST260*/261enum ASTNodeType { TYPE_ADD = 0, TYPE_MINUS = 1, TYPE_MUL = 2, TYPE_DIV = 3, TYPE_POWER = 4, TYPE_FRACTION = 5, TYPE_DOUBLE = 6 };262263struct ASTNode;264265union NodeData {266fraction frac;267double real;268pair<ASTNode*, ASTNode*> node;269270NodeData() {271real = 0;272}273};274275struct ASTNode {276ASTNodeType type;277NodeData data;278279ASTNode() {280type = TYPE_DOUBLE;281}282283~ASTNode() {284if (type != TYPE_FRACTION && type != TYPE_DOUBLE) {285delete data.node.first;286delete data.node.second;287}288}289};290291292293/*294* random ast295*/296enum cal_mode { MODE_FRACTION, MODE_REAL };297298inline ASTNode* random_value(cal_mode mode) {299ASTNode* node = new ASTNode();300int m, n;301switch (mode) {302case MODE_FRACTION:303node->type = TYPE_FRACTION;304m = rand() % (global_setting.max_num - 1) + 1;305n = rand() % (m * 5);306if (global_setting.has_fraction) {307node->data.frac = fraction(n, m);308}309else {310node->data.frac = fraction(m);311}312break;313314case MODE_REAL:315node->type = TYPE_DOUBLE;316double base = pow(10, global_setting.precision);317node->data.real = floor((rand() / (double)RAND_MAX)*global_setting.max_num*base) / base;318break;319}320return node;321}322323ASTNode* random_ast(cal_mode mode) {324int n = global_setting.max_opearators <= 1 ? 1 : rand() % (global_setting.max_opearators - 1) + 1;325ASTNode* num1 = random_value(mode);326for (int i = 0; i<n; i++) {327ASTNode* num2 = random_value(mode);328if (rand() % 2) swap(num1, num2);329int r = rand() % 17;330ASTNode* new_node = new ASTNode();331332333if (r-- == 16 && (num2->type == TYPE_FRACTION || num2->type == TYPE_FRACTION) && (num1->type != TYPE_POWER) && global_setting.has_power) {334if (mode == MODE_FRACTION) num2->data.frac = fraction(rand() % 4 + 1);335else num2->data.real = rand() % 2 + 2;336337new_node->type = TYPE_POWER;338new_node->data.node.first = num1;339new_node->data.node.second = num2;340}341else {342if (global_setting.has_mul_div) {343new_node->type = (ASTNodeType)(r / 4);344if (mode == MODE_FRACTION && !global_setting.has_fraction) {345r = rand() % 10;346if (r-- == 9) new_node->type = TYPE_DIV;347else new_node->type = (ASTNodeType)(r / 3);348}349}350else {351new_node->type = (ASTNodeType)(r / 8);352}353new_node->data.node.first = num1;354new_node->data.node.second = num2;355}356357num1 = new_node;358}359return num1;360}361362363long long hash_value;364ASTNode* calc_asttree(ASTNode* root) {365ASTNode* result = new ASTNode();366result->type = TYPE_FRACTION;367result->data.frac;368ASTNode* temp_a = new ASTNode();369ASTNode* temp_b = new ASTNode();370switch (root->type) {371case TYPE_FRACTION:372result->type = TYPE_FRACTION;373result->data.frac = root->data.frac;374break;375case TYPE_DOUBLE:376result->type = TYPE_DOUBLE;377result->data.real = root->data.real;378break;379case TYPE_ADD:380temp_a = calc_asttree(root->data.node.first);381temp_b = calc_asttree(root->data.node.second);382if (temp_a->type == TYPE_FRACTION && temp_b->type == TYPE_FRACTION) {383result->type = TYPE_FRACTION;384result->data.frac = temp_a->data.frac + temp_b->data.frac;385}386else {387result->type = TYPE_DOUBLE;388double a, b;389if (temp_a->type == TYPE_FRACTION) {390a = (double)temp_a->data.frac.numerator / (double)temp_a->data.frac.denominator;391}392else if (temp_a->type == TYPE_DOUBLE) {393a = temp_a->data.real;394}395if (temp_b->type == TYPE_FRACTION) {396b = (double)temp_b->data.frac.numerator / (double)temp_b->data.frac.denominator;397}398else if (temp_b->type == TYPE_DOUBLE) {399b = temp_b->data.real;400}401result->data.real = is_bad_value(a) || is_bad_value(b) ? INFINITY : (a + b);402}403break;404case TYPE_MINUS:405temp_a = calc_asttree(root->data.node.first);406temp_b = calc_asttree(root->data.node.second);407if (temp_a->type == TYPE_FRACTION && temp_b->type == TYPE_FRACTION) {408result->type = TYPE_FRACTION;409result->data.frac = temp_a->data.frac - temp_b->data.frac;410411}412else {413result->type = TYPE_DOUBLE;414double a, b;415if (temp_a->type == TYPE_FRACTION) {416a = (double)temp_a->data.frac.numerator / (double)temp_a->data.frac.denominator;417}418else if (temp_a->type == TYPE_DOUBLE) {419a = temp_a->data.real;420}421if (temp_b->type == TYPE_FRACTION) {422b = (double)temp_b->data.frac.numerator / (double)temp_b->data.frac.denominator;423}424else if (temp_b->type == TYPE_DOUBLE) {425b = temp_b->data.real;426}427result->data.real = is_bad_value(a) || is_bad_value(b) ? INFINITY : (a - b);428}429break;430case TYPE_MUL:431temp_a = calc_asttree(root->data.node.first);432temp_b = calc_asttree(root->data.node.second);433if (temp_a->type == TYPE_FRACTION && temp_b->type == TYPE_FRACTION) {434result->type = TYPE_FRACTION;435result->data.frac = temp_a->data.frac * temp_b->data.frac;436437}438else {439result->type = TYPE_DOUBLE;440double a, b;441if (temp_a->type == TYPE_FRACTION) {442a = (double)temp_a->data.frac.numerator / (double)temp_a->data.frac.denominator;443}444else if (temp_a->type == TYPE_DOUBLE) {445a = temp_a->data.real;446}447if (temp_b->type == TYPE_FRACTION) {448b = (double)temp_b->data.frac.numerator / (double)temp_b->data.frac.denominator;449}450else if (temp_b->type == TYPE_DOUBLE) {451b = temp_b->data.real;452}453result->data.real = is_bad_value(a) || is_bad_value(b) ? INFINITY : (a*b);454}455break;456case TYPE_DIV:457temp_a = calc_asttree(root->data.node.first);458temp_b = calc_asttree(root->data.node.second);459if (temp_a->type == TYPE_FRACTION && temp_b->type == TYPE_FRACTION) {460result->type = TYPE_FRACTION;461result->data.frac = temp_a->data.frac / temp_b->data.frac;462463}464else {465result->type = TYPE_DOUBLE;466double a, b;467if (temp_a->type == TYPE_FRACTION) {468a = (double)temp_a->data.frac.numerator / (double)temp_a->data.frac.denominator;469}470else if (temp_a->type == TYPE_DOUBLE) {471a = temp_a->data.real;472}473if (temp_b->type == TYPE_FRACTION) {474b = (double)temp_b->data.frac.numerator / (double)temp_b->data.frac.denominator;475}476else if (temp_b->type == TYPE_DOUBLE) {477b = temp_b->data.real;478}479result->data.real = is_bad_value(a) || is_bad_value(b) || fabs(b) <= 1e-3 ? INFINITY : (a / b);480}481break;482case TYPE_POWER:483temp_a = calc_asttree(root->data.node.first);484temp_b = calc_asttree(root->data.node.second);485if (temp_a->type == TYPE_FRACTION && temp_b->type == TYPE_FRACTION) {486result->type = TYPE_FRACTION;487result->data.frac = temp_a->data.frac ^ temp_b->data.frac;488489}490else {491result->type = TYPE_DOUBLE;492double a, b;493if (temp_a->type == TYPE_FRACTION) {494a = (double)temp_a->data.frac.numerator / (double)temp_a->data.frac.denominator;495}496else if (temp_a->type == TYPE_DOUBLE) {497a = temp_a->data.real;498}499if (temp_b->type == TYPE_FRACTION) {500b = (double)temp_b->data.frac.numerator / (double)temp_b->data.frac.denominator;501}502else if (temp_b->type == TYPE_DOUBLE) {503b = temp_b->data.real;504}505result->data.real = is_bad_value(a) || is_bad_value(b) ? INFINITY : powl(a, b);506}507break;508}509long long value = (long long)(root->type == TYPE_FRACTION ? (root->data.frac.numerator / (double)root->data.frac.denominator) : root->data.real);510hash_value = (hash_value * 19260817 + value) % (long long)(1e9 + 7);511delete temp_a;512delete temp_b;513if (result->type == TYPE_FRACTION) {514if ( (result->data.frac.denominator > global_setting.max_range*100 || result->data.frac.numerator < 0) ||515(result->data.frac.denominator != 1 && !global_setting.has_fraction)) {516result->data.frac.numerator = 1;517result->data.frac.denominator = 0;518}519} else if (result->type == TYPE_DOUBLE && (result->data.real <0|| result->data.real>global_setting.max_range*10)) {520result->data.real = INFINITY;521}522return result;523}524525ASTNode* ast_eval(ASTNode* root) {526hash_value = 0;527return calc_asttree(root);528}529530/*531* Expr := AddExpr | Expr + AddExpr532* AddExpr := MulExpr | AddExpr * MulExpr533* MulExpr := PowExpr | MulExpr ^ PowExpr534* PowExpr := Number | (Expr)535*/536enum ExprType { EXPR_EXPR, EXPR_ADDEXPR, EXPR_MULEXPR, EXPR_POWEXPR };537538void ast_output_expr(ASTNode* root, stringstream& ss);539void ast_output_addexpr(ASTNode* root, stringstream& ss);540void ast_output_mulexpr(ASTNode* root, stringstream& ss);541void ast_output_powexpr(ASTNode* root, stringstream& ss);542void ast_output_number(ASTNode* root, stringstream& ss);543544void ast_output_expr(ASTNode* root, stringstream& ss) {545switch (root->type) {546case TYPE_ADD:case TYPE_MINUS:547ast_output_expr(root->data.node.first, ss);548ss << (root->type == TYPE_ADD ? " + " : " - ");549ast_output_addexpr(root->data.node.second, ss);550break;551552default:553ast_output_addexpr(root, ss);554break;555}556}557558void ast_output_addexpr(ASTNode* root, stringstream& ss) {559switch (root->type) {560case TYPE_MUL:case TYPE_DIV:561ast_output_addexpr(root->data.node.first, ss);562ss << (root->type == TYPE_MUL ? " * " : " / ");563ast_output_mulexpr(root->data.node.second, ss);564break;565566default:567ast_output_mulexpr(root, ss);568break;569}570}571572void ast_output_mulexpr(ASTNode* root, stringstream& ss) {573switch (root->type) {574case TYPE_POWER:575ast_output_mulexpr(root->data.node.first, ss);576#ifdef DEBUG577ss << " ** ";578#elif defined(TEST)579ss << " ** ";580#else581ss << "^";582#endif583ast_output_powexpr(root->data.node.second, ss);584break;585default:586ast_output_powexpr(root, ss);587break;588}589}590591void ast_output_powexpr(ASTNode* root, stringstream& ss) {592switch (root->type) {593case TYPE_FRACTION:594ss << root->data.frac;595break;596case TYPE_DOUBLE:597ss << root->data.real;598break;599default:600ss << '(';601ast_output_expr(root, ss);602ss << ')';603break;604}605}606607set<long long> ans_set;608609CORE15_API void set_setting(610int max_opearators,611long max_range,612int precision,613int has_fraction,614int has_real,615int has_mul_div,616int has_power) {617618if (max_opearators != -1) global_setting.max_opearators = max_opearators;619if (max_range != -1) global_setting.max_range = max_range;620if (precision != -1) global_setting.precision = precision;621if (has_fraction != -1) global_setting.has_fraction = has_fraction != 0;622if (has_real != -1) global_setting.has_real = has_real != 0;623if (has_mul_div != -1) global_setting.has_mul_div = has_mul_div != 0;624if (has_power != -1) global_setting.has_power = has_power != 0;625global_setting.max_num = max_range>=20 ? max_range / 10 : max_range;626}627628#ifdef TEST629int c1=0,c2=0;630#endif631CORE15_API void generate(string* question, string* answer) {632cal_mode mode;633int magic = global_setting.has_fraction ? 32 : 3;634if (global_setting.has_real && rand() % magic == 0) {635mode = MODE_REAL;636} else{637mode = MODE_FRACTION;638}639question->clear();640answer->clear();641642ASTNode* node = random_ast(mode);643ASTNode* ret = ast_eval(node);644bool bad_value = false;645646stringstream s1, s2;647s1.setf(std::ios::fixed, std::ios::floatfield);648s2.setf(std::ios::fixed, std::ios::floatfield);649650s2.precision(global_setting.precision);651if (ret->type == TYPE_DOUBLE && !is_bad_value(ret->data.real)) {652s2 << ret->data.real;653}654else if (ret->type == TYPE_FRACTION && !is_bad_value(ret->data.frac)) {655#ifdef DEBUG656s2 << (ret->data.frac.numerator / (double)ret->data.frac.denominator);657#else658s2 << ret->data.frac;659#endif660}661else {662bad_value = true;663}664*answer = s2.str();665666if (bad_value || ans_set.find(hash_value) != ans_set.end()) {667generate(question, answer);668delete node;669delete ret;670return;671}672else {673ans_set.insert(hash_value);674}675676s1.precision(global_setting.precision);677ast_output_expr(node, s1);678*question = s1.str();679680delete node;681delete ret;682683#ifdef TEST684if(mode==MODE_FRACTION) c1++;685else c2++;686#endif687688return;689}690691692#ifdef DEBUG693// for unit test694int main() {695// todo: random696FILE* file = NULL;697const long long test_num = 100000;698const long long test_groups = 100;699for (long long i = 0; i<test_num; i++) {700if (i % (test_num / test_groups) == 0) {701stringstream ss;702ss << "test" << i / (test_num / test_groups) << ".py";703if (file) fclose(file);704file = fopen(ss.str().c_str(), "w");705}706string que, ans;707generate(&que, &ans);708fprintf(file, "assert(%lld>=0 and abs((%s)-(%s))<5e-2)\n", i, que.c_str(), ans.c_str());709}710fclose(file);711return 0;712}713#elif defined(TEST)714int main() {715srand(time(NULL));716for (long long i = 0; i<200; i++) {717string que, ans;718generate(&que, &ans);719cout << que << " = " << ans << endl;720}721cout<<c1<<" "<<c2<<endl;722return 0;723}724#endif
结对编程项目报告--四则运算CORE的更多相关文章
- 结对编程项目——四则运算vs版
结对编程项目--四则运算vs版 1)小伙伴信息: 学号:130201238 赵莹 博客地址:点我进入 小伙伴的博客 2)实现的功能: 实现带有用户界面的四则运算:将原只能在 ...
- 20175324王陈峤宇 2018-2019-2《Java程序设计》结对编程项目-四则运算 第一周 阶段性总结
20175324王陈峤宇 2018-2019-2<Java程序设计>结对编程项目-四则运算 第一周 阶段性总结 需求分析 这次的结对作业是要求我们利用栈来设计一个计算器. 自动生成四则运算 ...
- 20175229许钰玮 2018-2019-2《Java程序设计》结对编程项目-四则运算 第一周 阶段性总结
20175229许钰玮 2018-2019-2<Java程序设计>结对编程项目-四则运算 第一周 阶段性总结 需求分析 自动生成四则运算题目(加.减.乘.除). 既可以用前缀算法(波兰算法 ...
- 20175311胡济栋 2018-2019-2《Java程序设计》结对编程项目-四则运算 第二周 阶段性总结
20175311胡济栋 2018-2019-2<Java程序设计>结对编程项目-四则运算 第二周 阶段性总结 需求分析 这是利用栈来设计一个计算器的第二阶段总结. 自动生成四则运算的题目( ...
- 20175316盛茂淞 2018-2019-2《Java程序设计》结对编程项目-四则运算 第二周(6)
20175316与20175329 结对编程练习_四则运算(第二周) 1.需求分析 实现一个命令行程序,要求: 自动生成指定数量的小学四则运算题目(加.减.乘.除) 支持整数 统计正确率 支持多运算符 ...
- 软件工程启程篇章:结对编程和进阶四则运算(197 & 199)
0x01 :序言:无关的事 I wrote a sign called "Dead End" in front of myself, but love crossed it wit ...
- 结对编程项目总结(core2组)
结对编程项目总结(core2组) 作业---四则运算(Core 第二组) ----by 吴雪晴 PB16061514 齐天杨 PB16060706 一.项目简介 项目的任务为制作一个给(貌似是?) ...
- 2017-2018-2 20172323 『Java程序设计』课程 结对编程练习_四则运算
结对编程的好丽友 - 20172323 王禹涵:中缀转后缀 - 20172314 方艺雯:后缀表达式的计算 - 20172305 谭鑫:中缀表达式的输出 需求分析 能随机生成由使用者确定的任意多道四则 ...
- 20165101刘天野 2017-2018-2 《Java程序设计》 结对编程练习_四则运算(第二周)
20165101刘天野 2017-2018-2 <Java程序设计> 结对编程练习_四则运算(第二周) 一.需求分析 能随机生成n道四则运算题目,n由使用者输入 支持分数运算 支持多运算符 ...
随机推荐
- Scrapy框架: 登录网站
一.使用cookies登录网站 import scrapy class LoginSpider(scrapy.Spider): name = 'login' allowed_domains = ['x ...
- python面试题之如何解决验证码的问题,用什么模块,听过哪些人工打码平台?
如何解决验证码的问题,用什么模块,听过哪些人工打码平台? PIL.pytesser.tesseract模块 平台的话有:(打码平台特殊,不保证时效性) 云打码 挣码 斐斐打码 若快打码 超级鹰 本文首 ...
- CF1205B
CF1205B 由鸽巢原理n比较大的时候直接输出3 然后剩下的就可以跑最小环 #include<iostream> #include<cstdio> #include<c ...
- docker运行我们的容器
docker images docker pull nginx 运行 docker images 查看Nginx镜像是否获取成功,若为如下所示即为获取成功: docker run -p 8080:80 ...
- ubuntu安装goland
安装goland 首先下载goland https://www.jetbrains.com/zh/go/specials/go/go.html?utm_source=baidu&utm_med ...
- Tips using Manjaro
Set swappiness value The default swappiness value is set 60 as you can check it via the following co ...
- Git分布式版本控制系统(上)
Git分布式版本控制系统(上) 链接:https://pan.baidu.com/s/1CgaEv12cwfbs5RxcNpxdAg 提取码:fytm 复制这段内容后打开百度网盘手机App,操作更方便 ...
- 界面设计微信小程序
上一个周期将微信小程序的程序编完了,虽然还有很多需要修改的地方,大体已经完成.剩下的边角料以后再弄 这个周期来学习一下微信小程序的设计....好吧. 首先还是需要看一下微信的设计指南的.地址 http ...
- python爬虫环境1
转载 https://cuiqingcai.com/5052.html 1.1 python3安装 配置环境变量:随后点击“新建”,新建一个条目,将刚才复制的C:\Python36复制进去.这里需要 ...
- Java Collection - PriorityQueue 优先队列
总结 优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素,C++的优先队列每次取最大元素).这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序(na ...