[Question]
  [
Given a positive integer (0 and above, no maximum), convert it into a grade following these rules:
```
A = 100+  
B = 90 - 99  
C = 80 - 89  
D = 70 - 79  
E = 60 - 69  
F = 59 and less.
```
This felt a little boring, so make the grade a `+` if it's 7,8 or 9 and a `-` if it's 0,1 or 2. Ignore this for the F and A cases.
An example:
**Input:**
```
65
```
**Output:**
```
E
```
Test cases:
```
0  -> F
20 -> F
65 -> E
72 -> D-
75 -> D
80 -> C-
99 -> B+
102 -> A
864 -> A
```
No trailing spaces. One newline after output is fine, but keep it consistent. Functions and full programs are both fine.
This is code golf, so shortest code wins. This was inspired by an Ask Ubuntu question, [How to write a shell script to assign letter grades to numeric ranges?](https://askubuntu.com/questions/621466/how-to-write-a-shell-script-to-assign-letter-grades-to-numeric-ranges). The answers are in bash and python, so slightly spoilers.
---
**Leaderboard:**
Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.
To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:
```
# Language Name, N bytes
```
where `N` is the size of your submission. If you improve your score, you *can* keep old scores in the headline, by striking them through. For instance:
```
# Ruby, <s>104</s> <s>101</s> 96 bytes
```
```
var QUESTION_ID=49876;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),e.has_more?getAnswers():process()}})}function shouldHaveHeading(e){var a=!1,r=e.body_markdown.split("\n");try{a|=/^#/.test(e.body_markdown),a|=["-","="].indexOf(r[1][0])>-1,a&=LANGUAGE_REG.test(e.body_markdown)}catch(n){}return a}function shouldHaveScore(e){var a=!1;try{a|=SIZE_REG.test(e.body_markdown.split("\n")[0])}catch(r){}return a}function getAuthorName(e){return e.owner.display_name}function process(){answers=answers.filter(shouldHaveScore).filter(shouldHaveHeading),answers.sort(function(e,a){var r=+(e.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0],n=+(a.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0];return r-n});var e={},a=1,r=null,n=1;answers.forEach(function(s){var t=s.body_markdown.split("\n")[0],o=jQuery("#answer-template").html(),l=(t.match(NUMBER_REG)[0],(t.match(SIZE_REG)||[0])[0]),c=t.match(LANGUAGE_REG)[1],i=getAuthorName(s);l!=r&&(n=a),r=l,++a,o=o.replace("{{PLACE}}",n+".").replace("{{NAME}}",i).replace("{{LANGUAGE}}",c).replace("{{SIZE}}",l).replace("{{LINK}}",s.share_link),o=jQuery(o),jQuery("#answers").append(o),e[c]=e[c]||{lang:c,user:i,size:l,link:s.share_link}});var s=[];for(var t in e)e.hasOwnProperty(t)&&s.push(e[t]);s.sort(function(e,a){return e.lang>a.lang?1:e.lang<a.lang?-1:0});for(var o=0;o<s.length;++o){var l=jQuery("#language-template").html(),t=s[o];l=l.replace("{{LANGUAGE}}",t.lang).replace("{{NAME}}",t.user).replace("{{SIZE}}",t.size).replace("{{LINK}}",t.link),l=jQuery(l),jQuery("#languages").append(l)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",answers=[],page=1;getAnswers();var SIZE_REG=/\d+(?=[^\d&]*(?:&lt;(?:s&gt;[^&]*&lt;\/s&gt;|[^&]+&gt;)[^\d&]*)*$)/,NUMBER_REG=/\d+/,LANGUAGE_REG=/^#*\s*([^,]+)/;
```
```
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
```
```
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"><div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table></div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table></div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table><table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table>
```
  
[Answer]
# Python 2, ~~72~~ ~~70~~ 62 bytes
```
lambda n:"FA"[n>59:1+n/100]or chr(75-n/10)+"+-"[(n+3)%10/3::2]
```
This is an anonymous function that takes an int and returns the grade as a string.
(thanks to @MartinBüttner, @grc and @TheNumberOne for tips)
[Answer]
# CJam, ~~34 33~~ 32 bytes
```
riAmd)4/"- +"=S-\Ae<5e>_~'L+o5%<
```
Okay, I've tried multiple approaches now and am unable to get this below 33, so here goes the explanation:
```
ri                                 e# Read the input and convert to integer
  Amd                              e# Take divmod of the input with 10. This leaves the
                                   e# number/10 and number%10 on stack
     )4/                           e# Increment the mod by 1 and integer divide by 4.
        "- +"=S-                   e# This converts 0,1,2 to 0 and 7,8,9 to 2. Pick - or +
                                   e# respectively and remove space in case of 3,4,5 and 6
                \Ae<5e>            e# To the divisor by 10 scope it to range of [5,10]
                       _~          e# Take a copy and do number * -1 - 1
                         'L+       e# Add it to char L. This gets us the required grade
                            o      e# Output the grade. This removes it from stack
                             5%    e# We now have scoped divisor on stack. Do mod with 5
                               <   e# Both 5 and 10 will return 0, in which case, we don't
                                   e# want the + or -. So we do a substr(0, 0).
                                   e# 5 represents F and 10, A. For others, it will do
                                   e# substr(0,X) where X > 0. Since the string is only
                                   e# 1 char long, it doesn't affect at all.
```
*UPDATE*: 1 byte saved thanks to a pointer by Dennis
[Try it online here](http://cjam.aditsu.net/#code=riAmd)4%2F%22-%20%2B%22%3DS-%5CAe%3C5e%3E_~'L%2Bo5%25%3C&input=92)
[Answer]
# Retina, 43 + 15 = 58 bytes
```
...+
A
.[012]
$&-
.[789]
$&+
^9.
B
^8.
C
^7.
D
6.
E
\d.*
F
```
[**Retina**](https://github.com/mbuettner/retina) is a regex language created by Martin Büttner, where the odd-numbered files are the regex to match with, and the even-numbered files are what to replace it with. Each line is a separate file, so I've added 15 bytes for each additional file.
## Explanation
It starts by making anything with 3 or more digits an A. It adds a `-` if it is two-digit number ending with 0, 1, or 2, and `+` if it ends with 7, 8, or 9. The numbers are then mapped to their grade (e.g. a number starting with 9 is given a B). Any number left over is automatically an F. Unfortunately, `;`` must be prepended to all but to the last regex to suppress intermediate output. Update: version 0.5.0 has intermediate output off by default, allowing me to save a few bytes.
[Answer]
## C, 99 bytes
I'm new here, I hope I'm following the rules.
```
char b[3];char*f(n){b[1]=0;n<60?*b=70:n>99?*b=65:(*b=75-n/10,b[1]=n%10<3?45:n%10>6?43:0);return b;}
```
This function takes the mark as a parameter and returns the grade as a NULL-terminated string.
## Explanation
Added whitespace:
```
char b[3];
char *f(n) {
    b[1] = 0;
    n<60 ? *b = 70 :
    n>99 ? *b = 65 :
    (
        *b = 75 - n / 10,
        b[1] = n % 10 < 3 ? 45 : n % 10 > 6 ? 43 : 0
    );
    return b;
}
```
Global variables are automatically initialized to zero, so b is filled with NULLs. Since only the first two characters are ever touched, we only have to worry about putting a NULL in b[1] if the grade has only one character. This NULL is inserted at the very beginning of the function.
The n parameter is implicitly int. If the grade is less than 60, then it's set to 'F', if it's bigger than 99 it's set to 'A'.
In the other cases, the base grade is given by `'E' - (n - 60) / 10`, which simplifies to `75 - n / 10`. `n % 10` gets the units digit of the mark. If it's less than 3 then a - is appended, if it's bigger than 6 a + is appended, otherwise b[1] is nulled (which it already was).
## Test cases
```
#include <stdio.h>
char b[3];char*f(n){b[1]=0;n<60?*b=70:n>99?*b=65:(*b=75-n/10,b[1]=n%10<3?45:n%10>6?43:0);return b;}
int main() {
    printf("  0 -> %s\n", f(0));
    printf(" 20 -> %s\n", f(20));
    printf(" 65 -> %s\n", f(65));
    printf(" 72 -> %s\n", f(72));
    printf(" 75 -> %s\n", f(75));
    printf(" 80 -> %s\n", f(80));
    printf(" 99 -> %s\n", f(99));
    printf("102 -> %s\n", f(102));
    printf("864 -> %s\n", f(864));
    return 0;
}
Output:
  0 -> F
 20 -> F
 65 -> E
 72 -> D-
 75 -> D
 80 -> C-
 99 -> B+
102 -> A
864 -> A
```
[Answer]
# Pyth, 33 bytes
```
+C-75K@S[/QTT5)1<-@"- +"/heQ4d%K5
```
Try it online: [Demonstration](https://pyth.herokuapp.com/?code=%2BC-75K%40S%5B%2FQTT5)1%3C-%40%22-+%2B%22%2FheQ4d%25K5&input=80&debug=0) or [Test Suite](https://pyth.herokuapp.com/?code=FQ.Q%2B%2B%60Q%22+-%3E+%22%2BC-75K%40S%5B%2FQTT5)1%3C-%40%22-+%2B%22%2FheQ4d%25K5&input=%22Test+Cases%3A%22%0A0%0A20%0A65%0A72%0A75%0A80%0A99%0A102%0A864&debug=0)
### Explanation:
```
                                     implicit: Q = input
        [/QTT5)                      create the list [Q/10, 10, 5]
       S                             sort
      @        1                     take the element in the middle
     K                               store in K (this results in a number between 5 and 10)
  -75K                               75 - K
 C                                   char with ASCII-value ...
                  @"- +"/heQ4        "- +"[(Q%10 + 1) / 4]
                 -           d       remove spaces
                <             %K5    slice [:K%5]
+                                    add these two chars and print
```
[Answer]
# ><> (Fish), ~~78~~ 71 bytes
```
iii0)?/:0({:'6'(@@+?/'{'01.
;$-o:'4'(?\'7'(?;'+'o
 ;o'A'\   \'-'o;o'F'\
```
Method:
* We read the codepoints of first 3 characters `x,y,z` from the input. If a character is not present the value of its variable's will be `-1` implicitly. (`ord(c)` will mark the codepoint of the character `c`)
* If `z > 0` (3 digit input) print `A` and exit.
* If `x < ord('6') or y < 0` (input < 60) print `F` and exit.
* Print the character with codepoint `123 - x`.
* If `y < ord('4') print`-` and exit.
* If `y > ord('6') print`+` and exit.
* Exit.
[Answer]
# C, 67 65
Surprisingly, this is quite close to the python solution.
```
f(i){printf(i<60?"F":i>99?"A":"%c%s",75-i/10,"-\0+"+(i%10+1)/4);}
```
But in order for this program, to come to such great shortness, sacrifices had to be made:
* If an `F` or an `A` is printed `printf` doesn't even look at the
other arguments passed. This is a quite nasty hack.
* If `(i%10+1)/4` evaluates to `1` (no `+` or `-` should be appended to the grade), the `%s` formatter receives a pointer to a `\0` byte, so nothing is printed. Also quite funny, because I didn't know that you could take the address of an indexed string literal. (e.g. `&"string"[i]`) (**edit**: `"string"+i` is even *shorter*! Thanks @nutki)
Here the output of the program for the numbers 57 to 102.
I made it a hexdump, so we can be sure no weird `\0` bytes have been printed.
```
% seq 44 115 | xargs -n1 ./grade | xxd
0000000: 4646 4646 4646 4646 4646 4646 4646 4646  FFFFFFFFFFFFFFFF
0000010: 452d 452d 452d 4545 4545 452b 452b 452b  E-E-E-EEEEE+E+E+
0000020: 442d 442d 442d 4444 4444 442b 442b 442b  D-D-D-DDDDD+D+D+
0000030: 432d 432d 432d 4343 4343 432b 432b 432b  C-C-C-CCCCC+C+C+
0000040: 422d 422d 422d 4242 4242 422b 422b 422b  B-B-B-BBBBB+B+B+
0000050: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
```
The `main` method used:
```
main(c,v)char**v;{f(atoi(v[1]));}
```
[Answer]
# CJam, ~~41~~ ~~39~~ ~~37~~ 34 bytes
This is way too long, but I don't think I'll be golfing it further for now.
```
qiAmd'K@Ae<5e>:X-X5%g@)4/"- +"=*S-
```
[Test it here.](http://cjam.aditsu.net/#code=qiAmd'K%40Ae%3C5e%3E%3AX-X5%25g%40)4%2F%22-%20%2B%22%3D*S-&input=72) Or [run all test cases here.](http://cjam.aditsu.net/#code=qN%2F%7BS%2F0%3D%0A%0AiAmd'K%40Ae%3C5e%3E%3AX-X5%25g%40)4%2F%22-%20%2B%22%3D*S-%0A%0A%5DoNo%7D%2F&input=0%20%20-%3E%20F%0A20%20-%3E%20F%0A65%20-%3E%20E%0A72%20-%3E%20D-%0A75%20-%3E%20D%0A80%20-%3E%20C-%0A99%20-%3E%20B%2B%0A102%20-%3E%20A%0A864%20-%3E%20A)
Three bytes saved by Optimizer.
## Explanation
*(Slightly outdated)*
```
qi                                    e# Read input and convert to integer.
  'K1$                                e# Push the character K, then copy the input.
      A/                              e# Divide by 10.
        Ae<5e>                        e# Clamp the result to the range 5..10.";
              -                       e# Subtract from K to get the grade.
               _'Am                   e# Duplicate get difference to A.
                   5%g                e# Check that its neither 0 (A) nor 5 (F).
                      @               e# Pull up the other copy of the input.
                       A%)4/          e# ((i % 10) + 1) / 4
                            "- +"=    e# Use that to select -, space, or +.
                                  *   e# Multiply it with the earlier boolean so that
                                      e# it vanishes for A and F.
                                   S- e# Remove the space if there is one.
```
[Answer]
# GNU sed, 73 + 1 = 74 bytes
The + 1 is for the -r parameter.
```
s/^[1-5]?.$/F/
s/.{3,}/A/
s/[7-9]$/+/
s/[3-6]$//
s/[0-2]$/-/
y/9876/BCDE/
```
[Answer]
# Python 2, ~~94~~ ~~88~~ ~~84~~ 69 bytes
```
lambda g:g>99and'A'or[chr(75-g/10)+'-+'[g%10>2:1-(g%10>6)],'F'][g<60]
```
[Answer]
# JavaScript (ES6), 66 bytes
Straight.
```
F=n=>n<60?'F':n>99?'A':'EDCB'[n/10-6|0]+(n%10>6?'+':n%10<3?'-':'')
// TEST (in Firefox)
for(i=0;i<111;i++)document.write(i+'='+F(i)+' ')
```
[Answer]
# R, ~~107~~ ~~105~~ 99 bytes
Not a very good effort I'm afraid, but I will try and golf it more later.
```
cat(LETTERS[11-(r=min(max(scan(),59),100))%/%10],if(r>59&r<100)c('-','','+')[(r%%10+1)/4+1],sep='')
```
**Edit** Dropped a couple of `if`s. Fixed the case and an incorrect result for 100. ~~Now to get rid of the `ifelse`s~~. Got rid of `ifelse`s.
[Answer]
# Perl, 66 62 bytes
This can probably be golfed more. Also a different way might be better.
```
$_=$_>99?A:$_<60?F:s/\d$/$&>6?"+":$&<3?"-":""/re;y/9876/BCDE/
```
+1 for `-p`
Run with:
```
echo 72 | perl -pE'$_=$_>99?A:$_<60?F:s/\d$/$&>6?"+":$&<3?"-":""/re;y/9876/BCDE/'
```
[Answer]
# Javascript (ES6), ~~78~~ 79 bytes
This really isn't the smartest option, but I did what I could.
```
F=n=>'FEDCBA'[n[2]?5:n<60?0:n[0]-5]+(n[2]||n<60?'':'-+\n'[n[1]<3?0:n[1]>6?1:2])
```
Simply pass the grade **as a string**, and it will return it's grade letter.
The string part in **very** important.
You can check a testcase here:
```
console._RELAY_TO_DOC=true;
//non-es6 version:
function F(n){return 'FEDCBA'[n[2]?5:n<60?0:n[0]-5]+(n[2]||n<60?'':'-+\n'[n[1]<3?0:n[1]>6?1:2])}
var testcases=[0,20,65,72,75,77,80,90,99,100,102,180,1000],
    results={};
for(var i in testcases)
{
  results[testcases[i]]=F(testcases[i]+'');
}
console.log(results);
```
```
<script src="http://ismael-miguel.github.io/console-log-to-document/files/console.log.min.js"></script>
```
~~If the aditional space after the letter isn't allowed, I will happily remove it.~~ **It wasn't!** This increased my code by 1 byte, but nothing (too) serious.
[Answer]
# C#, ~~143~~ ~~127~~ ~~112~~ 88 bytes
```
string g(int n){return n>=100?"A":n<=59?"F":(char)(75-n/10)+(n%10>6?"+":n%10<3?"-":"");}
```
I tried to be clever by doing ASCII number mods, but it seems I wasn't alone!
Thanks to Tim for advice on lists instead of ifs.
Thanks to DarcyThomas for pointing out I could use nested ternary operators.
[Answer]
# Haskell, 78 bytes
The first line feels wasteful, costing 14 bytes, but I couldn't find a shorter version without it.
```
(#)=replicate
a="A":a
f=(!!)$60#"F"++[g:s|g<-"EDCB",s<-3#"-"++4#""++3#"+"]++a
```
## Explanation
The operator `#` is a shorthand for creating n copies of its second argument. List `a` is an infinite list of Strings "A". Function `f` indexes into a list of all grades for n=0,1,... The list comprehension builds the "middle part" of this list (grades E to B); `g` is a single Char that is prepended to the String `s` (which may be empty).
## Usage
```
ghci> map f [0,20,65,72,75,80,99,102,864]
["F","F","E","D-","D","C-","B+","A","A"]
```
[Answer]
## C, 102 bytes
```
int f(int h){int b,c;printf("%c%c",b?65:!c?70:75-h/10,!(b=h>99)*(c=h>59)*(((h%10<3)*45+(h%10>6)*43)));
```
}
## Usage
```
#include <stdio.h>
int f(int );
int main(){
    int c;
    scanf("%d",&c);
    f(c);
}
```
[Answer]
# dc, 52
```
[Anq]sa[Fnq]sf[q]sn16o?A~rd9<ad6>f20r-n1+4/d1=n45r-P
```
### Output
```
$ for i in {0,20,65,72,75,80,99,102,864}; do printf "{%s -> %s} " $i $(dc -e '[Anq]sa[Fnq]sf[q]sn16o?A~rd9<ad6>f20r-n1+4/d1=n45r-P' <<< $i); done
{0 -> F} {20 -> F} {65 -> E} {72 -> D-} {75 -> D} {80 -> C-} {99 -> B+} {102 -> A} {864 -> A} $ 
$ 
```
[Answer]
# TI-Basic, 79 74 76 Bytes
```
Input N
If N>99
105->N
sub("FFFFFFEDCBA",1+int(N.1),1
If Ans!="F
Ans+sub("---    +++",1+fPart(N.1),1
Ans
```
[Answer]
# TI-BASIC, ~~69~~ ~~68~~ 66 bytes
```
.1Ans
sub("F?E-E+D-D+C-C+B-B+A",1+2max(0,min(9,int(2Ans)-11)),int(e^(Ans<10 and Ans≥6 and iPart(2.2-5fPart(Ans
```
TI-BASIC is not good for string manipulation.
Input on the calculator homescreen, in the form of [number]:[program name].
Formatted:
```
.1Ans
sub(                      //Syntax for the substring command is sub(string, index, length)
    "F?E-E+D-D+C-C+B-B+A"                  //String that encodes possible grades
    ,1+2max(0,min(9,            ))         //Starts at "F" if input <60, "A" if >=100
                   int(2Ans)-11           //(Input-55)/5, so starts at "E" from 60 to 64,
                                          //second E from 65-69, D from 70 to 74, &c.
    ,int(e^(                                   //length 1 if false, 2 (includes +/-) if true
            Ans<10 and Ans≥6 and               //grade between 60 and 100        
                                 iPart(               //1 if abs. val. of below >= 0.2
                                       2.2-5fPart(Ans  //2.2-.5(last digit)    
```
This can probably be golfed further.
[Answer]
# C#, 82 bytes
```
Func<int,string>g=s=>s>99?"A":s<60?"F":(char)(75-s/10)+(s%10<3?"-":s%10>6?"+":"");
```
Here's a [fiddle](https://dotnetfiddle.net/5lFuU5) with some test-cases.
[Answer]
# JavaScript (ES6), ~~86~~ 83 bytes
What's really eating up characters is the `String.fromCharCode` and the +/- condition... I strongly suspect there's a clever way to shorten at least one of them.
```
f=n=>n>99?'A':n<60?'F':String.fromCharCode(75.9-n/10|0)+(n%10<3?'-':n%10>6?'+':'');
```
[Answer]
# PHP5.5, 73 bytes
Once again, not the shortest one.
But it works!
```
<?=($n=$_GET[n])<59?F:($n>99?A:'BCDE'[$n[0]-6].'+-'[$n[1]<3?1:2*$n[1]<5])
```
I've classified it under PHP5.5 instead of just PHP since this uses syntax that is only valid for PHP5.5 and PHP5.6.
You can read about string and array dereferencing in the manual:  
<http://php.net/manual/en/migration55.new-features.php>
[Answer]
# Perl, 52
```
#!perl -p
$_=$_>99?A:$_<60?F:"$_"^"s";y/JK7890-6/BC+++\-\--/d
```
[Answer]
# Ruby, 58 Bytes
Couldn't believe that there are no Ruby ones here. On reflection it's fairly similar to some that are here already but anyway:
```
->x{x<60?'F':x>99?'A':(75-x/10).chr+'+-'[(x+3)%10/3].to_s}
```
[Try it here](http://rubyfiddle.com/riddles/0c011)
[Answer]
# Excel, 100 bytes
```
=IF(A1<60,"F",IF(A1>99,"A",MID("EDCB",INT(A1/10)-5,1)&IF(MOD(A1,10)<3,"-",IF(MOD(A1,10)>6,"+",""))))
```
]